use super::cmp::CanonicalOrd;
use super::iana::{Class, Rtype};
use super::name::{ParsedDname, ToDname};
use super::wire::{Composer, ParseError};
use core::cmp::Ordering;
use core::{fmt, hash};
use octseq::octets::{Octets, OctetsFrom};
use octseq::parse::Parser;
#[derive(Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Question<N> {
qname: N,
qtype: Rtype,
qclass: Class,
}
impl<N> Question<N> {
pub fn new(qname: N, qtype: Rtype, qclass: Class) -> Self {
Question {
qname,
qtype,
qclass,
}
}
pub fn new_in(qname: N, qtype: Rtype) -> Self {
Question {
qname,
qtype,
qclass: Class::In,
}
}
pub fn into_qname(self) -> N {
self.qname
}
}
impl<N: ToDname> Question<N> {
pub fn qname(&self) -> &N {
&self.qname
}
pub fn qtype(&self) -> Rtype {
self.qtype
}
pub fn qclass(&self) -> Class {
self.qclass
}
}
impl<Octs> Question<ParsedDname<Octs>> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Ok(Question::new(
ParsedDname::parse(parser)?,
Rtype::parse(parser)?,
Class::parse(parser)?,
))
}
}
impl<N: ToDname> Question<N> {
pub fn compose<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
target.append_compressed_dname(&self.qname)?;
self.qtype.compose(target)?;
self.qclass.compose(target)
}
}
impl<N: ToDname> From<(N, Rtype, Class)> for Question<N> {
fn from((name, rtype, class): (N, Rtype, Class)) -> Self {
Question::new(name, rtype, class)
}
}
impl<N: ToDname> From<(N, Rtype)> for Question<N> {
fn from((name, rtype): (N, Rtype)) -> Self {
Question::new(name, rtype, Class::In)
}
}
impl<Name, SrcName> OctetsFrom<Question<SrcName>> for Question<Name>
where
Name: OctetsFrom<SrcName>,
{
type Error = Name::Error;
fn try_octets_from(
source: Question<SrcName>,
) -> Result<Self, Self::Error> {
Ok(Question::new(
Name::try_octets_from(source.qname)?,
source.qtype,
source.qclass,
))
}
}
impl<N, NN> PartialEq<Question<NN>> for Question<N>
where
N: ToDname,
NN: ToDname,
{
fn eq(&self, other: &Question<NN>) -> bool {
self.qname.name_eq(&other.qname)
&& self.qtype == other.qtype
&& self.qclass == other.qclass
}
}
impl<N: ToDname> Eq for Question<N> {}
impl<N, NN> PartialOrd<Question<NN>> for Question<N>
where
N: ToDname,
NN: ToDname,
{
fn partial_cmp(&self, other: &Question<NN>) -> Option<Ordering> {
match self.qname.name_cmp(&other.qname) {
Ordering::Equal => {}
other => return Some(other),
}
match self.qtype.partial_cmp(&other.qtype) {
Some(Ordering::Equal) => {}
other => return other,
}
self.qclass.partial_cmp(&other.qclass)
}
}
impl<N, NN> CanonicalOrd<Question<NN>> for Question<N>
where
N: ToDname,
NN: ToDname,
{
fn canonical_cmp(&self, other: &Question<NN>) -> Ordering {
match self.qname.lowercase_composed_cmp(&other.qname) {
Ordering::Equal => {}
other => return other,
}
match self.qtype.cmp(&other.qtype) {
Ordering::Equal => {}
other => return other,
}
self.qclass.cmp(&other.qclass)
}
}
impl<N: ToDname> Ord for Question<N> {
fn cmp(&self, other: &Self) -> Ordering {
match self.qname.name_cmp(&other.qname) {
Ordering::Equal => {}
other => return other,
}
match self.qtype.cmp(&other.qtype) {
Ordering::Equal => {}
other => return other,
}
self.qclass.cmp(&other.qclass)
}
}
impl<N: hash::Hash> hash::Hash for Question<N> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.qname.hash(state);
self.qtype.hash(state);
self.qclass.hash(state);
}
}
impl<N: fmt::Display> fmt::Display for Question<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.\t{}\t{}", self.qname, self.qtype, self.qclass)
}
}
impl<N: fmt::Debug> fmt::Debug for Question<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Question")
.field("qname", &self.qname)
.field("qtype", &self.qtype)
.field("qclass", &self.qclass)
.finish()
}
}
pub trait ComposeQuestion {
fn compose_question<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError>;
}
impl<'a, Q: ComposeQuestion> ComposeQuestion for &'a Q {
fn compose_question<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
(*self).compose_question(target)
}
}
impl<Name: ToDname> ComposeQuestion for Question<Name> {
fn compose_question<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
self.compose(target)
}
}
impl<Name: ToDname> ComposeQuestion for (Name, Rtype, Class) {
fn compose_question<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
Question::new(&self.0, self.1, self.2).compose(target)
}
}
impl<Name: ToDname> ComposeQuestion for (Name, Rtype) {
fn compose_question<Target: Composer + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
Question::new(&self.0, self.1, Class::In).compose(target)
}
}