use super::cmp::CanonicalOrd;
use super::iana::Rtype;
use super::octets::{
Compose, OctetsBuilder, OctetsFrom, OctetsRef, Parse, ParseError, Parser,
ShortBuf,
};
#[cfg(feature = "master")]
use crate::master::scan::{
CharSource, Scan, ScanError, Scanner, SyntaxError,
};
#[cfg(feature = "master")]
use bytes::{BufMut, Bytes, BytesMut};
use core::cmp::Ordering;
use core::fmt;
pub trait RecordData: Compose + Sized {
fn rtype(&self) -> Rtype;
}
pub trait ParseRecordData<Ref>: RecordData {
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Ref>,
) -> Result<Option<Self>, ParseError>;
}
pub trait RtypeRecordData {
const RTYPE: Rtype;
}
impl<T: RtypeRecordData + Compose + Sized> RecordData for T {
fn rtype(&self) -> Rtype {
Self::RTYPE
}
}
impl<Octets, T> ParseRecordData<Octets> for T
where
T: RtypeRecordData + Parse<Octets> + Compose + Sized,
{
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Octets>,
) -> Result<Option<Self>, ParseError> {
if rtype == Self::RTYPE {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnknownRecordData<Octets> {
rtype: Rtype,
#[cfg_attr(
feature = "serde",
serde(
serialize_with = "crate::base::octets::SerializeOctets::serialize_octets",
deserialize_with = "crate::base::octets::DeserializeOctets::deserialize_octets",
bound(
serialize = "Octets: crate::base::octets::SerializeOctets",
deserialize = "Octets: crate::base::octets::DeserializeOctets<'de>",
)
)
)]
data: Octets,
}
impl<Octets> UnknownRecordData<Octets> {
pub fn from_octets(rtype: Rtype, data: Octets) -> Self {
UnknownRecordData { rtype, data }
}
pub fn rtype(&self) -> Rtype {
self.rtype
}
pub fn data(&self) -> &Octets {
&self.data
}
}
#[cfg(feature = "master")]
impl UnknownRecordData<Bytes> {
pub fn scan<C: CharSource>(
rtype: Rtype,
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
scanner.skip_literal("\\#")?;
let mut len = u16::scan(scanner)? as usize;
let mut res = BytesMut::with_capacity(len);
while len > 0 {
len = scanner.scan_word(
(&mut res, len, None), |&mut (ref mut res, ref mut len, ref mut first), symbol| {
if *len == 0 {
return Err(SyntaxError::LongGenericData);
}
let ch = symbol.into_digit(16)? as u8;
if let Some(ch1) = *first {
res.put_u8(ch1 << 4 | ch);
*len -= 1;
} else {
*first = Some(ch)
}
Ok(())
},
|(_, len, first)| {
if first.is_some() {
Err(SyntaxError::UnevenHexString)
} else {
Ok(len)
}
},
)?
}
Ok(UnknownRecordData::from_octets(rtype, res.freeze()))
}
}
impl<Octets, SrcOctets> OctetsFrom<UnknownRecordData<SrcOctets>>
for UnknownRecordData<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(
source: UnknownRecordData<SrcOctets>,
) -> Result<Self, ShortBuf> {
Ok(UnknownRecordData {
rtype: source.rtype,
data: Octets::octets_from(source.data)?,
})
}
}
impl<Octets, Other> PartialEq<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn eq(&self, other: &UnknownRecordData<Other>) -> bool {
self.data.as_ref().eq(other.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Eq for UnknownRecordData<Octets> {}
impl<Octets, Other> PartialOrd<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn partial_cmp(
&self,
other: &UnknownRecordData<Other>,
) -> Option<Ordering> {
self.data.as_ref().partial_cmp(other.data.as_ref())
}
}
impl<Octets, Other> CanonicalOrd<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn canonical_cmp(&self, other: &UnknownRecordData<Other>) -> Ordering {
self.data.as_ref().cmp(other.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Ord for UnknownRecordData<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
self.data.as_ref().cmp(other.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Compose for UnknownRecordData<Octets> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T,
) -> Result<(), ShortBuf> {
target.append_slice(self.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> RecordData for UnknownRecordData<Octets> {
fn rtype(&self) -> Rtype {
self.rtype
}
}
impl<Octets, Ref> ParseRecordData<Ref> for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Ref: OctetsRef<Range = Octets>,
{
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Ref>,
) -> Result<Option<Self>, ParseError> {
let rdlen = parser.remaining();
parser
.parse_octets(rdlen)
.map(|data| Some(Self::from_octets(rtype, data)))
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for UnknownRecordData<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\\# {}", self.data.as_ref().len())?;
for ch in self.data.as_ref() {
write!(f, " {:02x}", *ch)?
}
Ok(())
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for UnknownRecordData<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("UnknownRecordData(")?;
fmt::Display::fmt(self, f)?;
f.write_str(")")
}
}