use core::{fmt, hash};
use core::cmp::Ordering;
use super::cmp::CanonicalOrd;
use super::iana::{Class, Rtype};
use super::name::{ParsedDname, ToDname};
use super::octets::{
Compose, OctetsBuilder, OctetsRef, Parse, Parser, ParseError, ShortBuf
};
use super::rdata::{RecordData, ParseRecordData};
#[derive(Clone)]
pub struct Record<Name, Data> {
owner: Name,
class: Class,
ttl: u32,
data: Data
}
impl<Name, Data> Record<Name, Data> {
pub fn new(owner: Name, class: Class, ttl: u32, data: Data) -> Self {
Record { owner, class, ttl, data }
}
pub fn from_record<NN, DD>(record: Record<NN, DD>) -> Self
where Name: From<NN>, Data: From<DD> {
Self::new(
record.owner.into(),
record.class,
record.ttl,
record.data.into()
)
}
pub fn owner(&self) -> &Name {
&self.owner
}
pub fn rtype(&self) -> Rtype
where Data: RecordData {
self.data.rtype()
}
pub fn class(&self) -> Class {
self.class
}
pub fn set_class(&mut self, class: Class) {
self.class = class
}
pub fn ttl(&self) -> u32 {
self.ttl
}
pub fn set_ttl(&mut self, ttl: u32) {
self.ttl = ttl
}
pub fn data(&self) -> &Data {
&self.data
}
pub fn data_mut(&mut self) -> &mut Data {
&mut self.data
}
pub fn into_data(self) -> Data {
self.data
}
}
impl<N, D> From<(N, Class, u32, D)> for Record<N, D> {
fn from((owner, class, ttl, data): (N, Class, u32, D)) -> Self {
Self::new(owner, class, ttl, data)
}
}
impl<N, D> From<(N, u32, D)> for Record<N, D> {
fn from((owner, ttl, data): (N, u32, D)) -> Self {
Self::new(owner, Class::In, ttl, data)
}
}
impl<N, NN, D, DD> PartialEq<Record<NN, DD>> for Record<N, D>
where N: PartialEq<NN>, D: RecordData + PartialEq<DD>, DD: RecordData {
fn eq(&self, other: &Record<NN, DD>) -> bool {
self.owner == other.owner
&& self.class == other.class
&& self.data == other.data
}
}
impl<N: Eq, D: RecordData + Eq> Eq for Record<N, D> { }
impl<N, NN, D, DD> PartialOrd<Record<NN, DD>> for Record<N, D>
where N: PartialOrd<NN>, D: RecordData + PartialOrd<DD>, DD: RecordData {
fn partial_cmp(&self, other: &Record<NN, DD>) -> Option<Ordering> {
match self.owner.partial_cmp(&other.owner) {
Some(Ordering::Equal) => { }
res => return res
}
match self.class.partial_cmp(&other.class) {
Some(Ordering::Equal) => { }
res => return res
}
self.data.partial_cmp(&other.data)
}
}
impl<N, D> Ord for Record<N, D>
where N: Ord, D: RecordData + Ord {
fn cmp(&self, other: &Self) -> Ordering {
match self.owner.cmp(&other.owner) {
Ordering::Equal => { }
res => return res
}
match self.class.cmp(&other.class) {
Ordering::Equal => { }
res => return res
}
self.data.cmp(&other.data)
}
}
impl<N, NN, D, DD> CanonicalOrd<Record<NN, DD>> for Record<N, D>
where N: ToDname, NN: ToDname, D: RecordData + CanonicalOrd<DD>, DD: RecordData {
fn canonical_cmp(&self, other: &Record<NN, DD>) -> Ordering {
match self.class.cmp(&other.class) {
Ordering::Equal => { }
res => return res
}
match self.owner.name_cmp(&other.owner) {
Ordering::Equal => { }
res => return res
}
match self.rtype().cmp(&other.rtype()) {
Ordering::Equal => { }
res => return res
}
self.data.canonical_cmp(&other.data)
}
}
impl<Name, Data> hash::Hash for Record<Name, Data>
where Name: hash::Hash, Data: hash::Hash {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.owner.hash(state);
self.class.hash(state);
self.ttl.hash(state);
self.data.hash(state);
}
}
impl<Ref, Data> Parse<Ref> for Option<Record<ParsedDname<Ref>, Data>>
where Ref: OctetsRef, Data: ParseRecordData<Ref> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let header = RecordHeader::parse(parser)?;
header.parse_into_record(parser)
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
ParsedRecord::skip(parser)
}
}
impl<N: ToDname, D: RecordData> Compose for Record<N, D> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
target.append_compressed_dname(&self.owner)?;
self.data.rtype().compose(target)?;
self.class.compose(target)?;
self.ttl.compose(target)?;
target.u16_len_prefixed(|target| self.data.compose(target))
})
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
self.owner.compose_canonical(target)?;
self.data.rtype().compose(target)?;
self.class.compose(target)?;
self.ttl.compose(target)?;
target.u16_len_prefixed(|target| {
self.data.compose_canonical(target)
})
})
}
}
impl<Name, Data> fmt::Display for Record<Name, Data>
where Name: fmt::Display, Data: RecordData + fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"{}. {} {} {} {}",
self.owner, self.ttl, self.class, self.data.rtype(),
self.data
)
}
}
impl<Name, Data> fmt::Debug for Record<Name, Data>
where Name: fmt::Debug, Data: fmt::Debug {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Record")
.field("owner", &self.owner)
.field("class", &self.class)
.field("ttl", &self.ttl)
.field("data", &self.data)
.finish()
}
}
pub trait AsRecord {
type Name: ToDname;
type Data: RecordData;
fn owner(&self) -> &Self::Name;
fn class(&self) -> Class;
fn ttl(&self) -> u32;
fn data(&self) -> &Self::Data;
fn compose_record<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
target.append_compressed_dname(self.owner())?;
self.data().rtype().compose(target)?;
self.class().compose(target)?;
self.ttl().compose(target)?;
target.u16_len_prefixed(|target| self.data().compose(target))
})
}
fn compose_record_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
self.owner().compose_canonical(target)?;
self.data().rtype().compose(target)?;
self.class().compose(target)?;
self.ttl().compose(target)?;
target.u16_len_prefixed(|target| {
self.data().compose_canonical(target)
})
})
}
}
impl<'a, T: AsRecord> AsRecord for &'a T {
type Name = T::Name;
type Data = T::Data;
fn owner(&self) -> &Self::Name { (*self).owner() }
fn class(&self) -> Class { (*self).class() }
fn ttl(&self) -> u32 { (*self).ttl() }
fn data(&self) -> &Self::Data { (*self).data() }
}
impl<Name: ToDname, Data: RecordData> AsRecord for Record<Name, Data> {
type Name = Name;
type Data = Data;
fn owner(&self) -> &Self::Name { Self::owner(self) }
fn class(&self) -> Class { Self::class(self) }
fn ttl(&self) -> u32 { Self::ttl(self) }
fn data(&self) -> &Self::Data { Self::data(self) }
}
impl<Name: ToDname, Data: RecordData> AsRecord for (Name, Class, u32, Data) {
type Name = Name;
type Data = Data;
fn owner(&self) -> &Self::Name { &self.0 }
fn class(&self) -> Class { self.1 }
fn ttl(&self) -> u32 { self.2 }
fn data(&self) -> &Self::Data { &self.3 }
}
impl<Name: ToDname, Data: RecordData> AsRecord for (Name, u32, Data) {
type Name = Name;
type Data = Data;
fn owner(&self) -> &Self::Name { &self.0 }
fn class(&self) -> Class { Class::In }
fn ttl(&self) -> u32 { self.1 }
fn data(&self) -> &Self::Data { &self.2 }
}
#[derive(Clone)]
pub struct RecordHeader<Name> {
owner: Name,
rtype: Rtype,
class: Class,
ttl: u32,
rdlen: u16,
}
impl<Name> RecordHeader<Name> {
pub fn new(
owner: Name,
rtype: Rtype,
class: Class,
ttl: u32,
rdlen: u16
) -> Self {
RecordHeader { owner, rtype, class, ttl, rdlen }
}
}
impl<Name> RecordHeader<Name> {
pub fn parse_and_skip<Ref>(
parser: &mut Parser<Ref>
) -> Result<Self, ParseError>
where Self: Parse<Ref>, Ref: OctetsRef {
let header = Self::parse(parser)?;
match parser.advance(header.rdlen() as usize) {
Ok(()) => Ok(header),
Err(_) => Err(ParseError::ShortInput),
}
}
}
impl RecordHeader<()> {
fn parse_rdlen<Ref: OctetsRef>(
parser: &mut Parser<Ref>
) -> Result<u16, ParseError> {
ParsedDname::skip(parser)?;
Rtype::skip(parser)?;
Class::skip(parser)?;
u32::skip(parser)?;
Ok(u16::parse(parser)?)
}
}
impl<Ref: OctetsRef> RecordHeader<ParsedDname<Ref>> {
pub fn parse_into_record<Data>(
self,
parser: &mut Parser<Ref>
) -> Result<Option<Record<ParsedDname<Ref>, Data>>, ParseError>
where Data: ParseRecordData<Ref> {
parser.parse_block(self.rdlen as usize, |parser| {
match Data::parse_data(self.rtype, parser)? {
Some(data) => {
Ok(Some(Record::new(
self.owner, self.class, self.ttl, data
)))
}
None => {
parser.advance_to_end();
Ok(None)
}
}
})
}
}
impl<Name> RecordHeader<Name> {
pub fn owner(&self) -> &Name {
&self.owner
}
pub fn rtype(&self) -> Rtype {
self.rtype
}
pub fn class(&self) -> Class {
self.class
}
pub fn ttl(&self) -> u32 {
self.ttl
}
pub fn rdlen(&self) -> u16 {
self.rdlen
}
pub fn into_record<Data>(self, data: Data) -> Record<Name, Data> {
Record::new(self.owner, self.class, self.ttl, data)
}
}
impl<Name, NName> PartialEq<RecordHeader<NName>> for RecordHeader<Name>
where Name: ToDname, NName: ToDname {
fn eq(&self, other: &RecordHeader<NName>) -> bool {
self.owner.name_eq(&other.owner)
&& self.rtype == other.rtype
&& self.class == other.class
&& self.ttl == other.ttl
&& self.rdlen == other.rdlen
}
}
impl<Name: ToDname> Eq for RecordHeader<Name> { }
impl<Name, NName> PartialOrd<RecordHeader<NName>> for RecordHeader<Name>
where Name: ToDname, NName: ToDname {
fn partial_cmp(&self, other: &RecordHeader<NName>) -> Option<Ordering> {
match self.owner.name_cmp(&other.owner) {
Ordering::Equal => { }
other => return Some(other)
}
match self.rtype.partial_cmp(&other.rtype) {
Some(Ordering::Equal) => { }
other => return other
}
match self.class.partial_cmp(&other.class) {
Some(Ordering::Equal) => { }
other => return other
}
match self.ttl.partial_cmp(&other.ttl) {
Some(Ordering::Equal) => { }
other => return other
}
self.rdlen.partial_cmp(&other.rdlen)
}
}
impl<Name: ToDname> Ord for RecordHeader<Name> {
fn cmp(&self, other: &Self) -> Ordering {
match self.owner.name_cmp(&other.owner) {
Ordering::Equal => { }
other => return other
}
match self.rtype.cmp(&other.rtype) {
Ordering::Equal => { }
other => return other
}
match self.class.cmp(&other.class) {
Ordering::Equal => { }
other => return other
}
match self.ttl.cmp(&other.ttl) {
Ordering::Equal => { }
other => return other
}
self.rdlen.cmp(&other.rdlen)
}
}
impl<Name: hash::Hash> hash::Hash for RecordHeader<Name> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.owner.hash(state);
self.rtype.hash(state);
self.class.hash(state);
self.ttl.hash(state);
self.rdlen.hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for RecordHeader<ParsedDname<Ref>> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
Ok(RecordHeader::new(
ParsedDname::parse(parser)?,
Rtype::parse(parser)?,
Class::parse(parser)?,
u32::parse(parser)?,
parser.parse_u16()?
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
ParsedDname::skip(parser)?;
Rtype::skip(parser)?;
Class::skip(parser)?;
u32::skip(parser)?;
u16::skip(parser)?;
Ok(())
}
}
impl<Name: Compose> Compose for RecordHeader<Name> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.owner.compose(buf)?;
self.rtype.compose(buf)?;
self.class.compose(buf)?;
self.ttl.compose(buf)?;
self.rdlen.compose(buf)
})
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.owner.compose_canonical(buf)?;
self.rtype.compose(buf)?;
self.class.compose(buf)?;
self.ttl.compose(buf)?;
self.rdlen.compose(buf)
})
}
}
impl<Name: fmt::Debug> fmt::Debug for RecordHeader<Name> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RecordHeader")
.field("owner", &self.owner)
.field("rtype", &self.rtype)
.field("class", &self.class)
.field("ttl", &self.ttl)
.field("rdlen", &self.rdlen)
.finish()
}
}
#[derive(Clone)]
pub struct ParsedRecord<Ref> {
header: RecordHeader<ParsedDname<Ref>>,
data: Parser<Ref>,
}
impl<Ref> ParsedRecord<Ref> {
pub fn new(
header: RecordHeader<ParsedDname<Ref>>,
data: Parser<Ref>
) -> Self {
ParsedRecord { header, data }
}
pub fn owner(&self) -> &ParsedDname<Ref> {
self.header.owner()
}
pub fn rtype(&self) -> Rtype {
self.header.rtype()
}
pub fn class(&self) -> Class {
self.header.class()
}
pub fn ttl(&self) -> u32 {
self.header.ttl()
}
pub fn rdlen(&self) -> u16 {
self.header.rdlen()
}
}
impl<Ref: OctetsRef> ParsedRecord<Ref> {
pub fn to_record<Data>(
&self
) -> Result<Option<Record<ParsedDname<Ref>, Data>>, ParseError>
where Data: ParseRecordData<Ref> {
self.header.clone().parse_into_record(&mut self.data.clone())
}
pub fn into_record<Data>(
mut self
) -> Result<Option<Record<ParsedDname<Ref>, Data>>, ParseError>
where Data: ParseRecordData<Ref> {
self.header.parse_into_record(&mut self.data)
}
}
impl<Ref, OtherRef> PartialEq<ParsedRecord<OtherRef>> for ParsedRecord<Ref>
where Ref: OctetsRef, OtherRef: OctetsRef {
fn eq(&self, other: &ParsedRecord<OtherRef>) -> bool {
self.header == other.header
&& self.data.peek(self.header.rdlen() as usize).eq(
&other.data.peek(other.header.rdlen() as usize)
)
}
}
impl<Ref: OctetsRef> Eq for ParsedRecord<Ref> { }
impl<Ref: OctetsRef> Parse<Ref> for ParsedRecord<Ref> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let header = RecordHeader::parse(parser)?;
let data = *parser;
parser.advance(header.rdlen() as usize)?;
Ok(Self::new(header, data))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
let rdlen = RecordHeader::parse_rdlen(parser)?;
parser.advance(rdlen as usize)?;
Ok(())
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RecordParseError<N, D> {
Name(N),
Data(D),
ShortBuf,
}
impl<N, D> fmt::Display for RecordParseError<N, D>
where N: fmt::Display, D: fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
RecordParseError::Name(ref name) => name.fmt(f),
RecordParseError::Data(ref data) => data.fmt(f),
RecordParseError::ShortBuf => {
f.write_str("unexpected end of buffer")
}
}
}
}
#[cfg(feature = "std")]
impl<N, D> std::error::Error for RecordParseError<N, D>
where N: std::error::Error, D: std::error::Error { }
impl<N, D> From<ShortBuf> for RecordParseError<N, D> {
fn from(_: ShortBuf) -> Self {
RecordParseError::ShortBuf
}
}