use std::fmt;
use bytes::{BufMut, Bytes, BytesMut};
use failure::Fail;
use ::iana::Rtype;
use ::master::scan::{CharSource, Scan, Scanner, ScanError, SyntaxError};
use super::compose::{Compose, Compress, Compressor};
use super::parse::{ParseAll, Parser, ShortBuf};
pub trait RecordData: Compose + Compress + Sized {
fn rtype(&self) -> Rtype;
}
pub trait ParseRecordData: RecordData {
type Err: Fail;
fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
-> Result<Option<Self>, Self::Err>;
}
pub trait RtypeRecordData {
const RTYPE: Rtype;
}
impl<T: RtypeRecordData + Compose + Compress + Sized> RecordData for T {
fn rtype(&self) -> Rtype { Self::RTYPE }
}
impl<T: RtypeRecordData + ParseAll + Compose + Compress + Sized>
ParseRecordData for T {
type Err = <Self as ParseAll>::Err;
fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
-> Result<Option<Self>, Self::Err> {
if rtype == Self::RTYPE {
Self::parse_all(parser, rdlen).map(Some)
}
else {
Ok(None)
}
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct UnknownRecordData {
rtype: Rtype,
data: Bytes,
}
impl UnknownRecordData {
pub fn from_bytes(rtype: Rtype, data: Bytes) -> Self {
UnknownRecordData { rtype, data }
}
pub fn rtype(&self) -> Rtype {
self.rtype
}
pub fn data(&self) -> &Bytes {
&self.data
}
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_bytes(rtype, res.freeze()))
}
}
impl Compose for UnknownRecordData {
fn compose_len(&self) -> usize {
self.data.len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(self.data.as_ref())
}
}
impl Compress for UnknownRecordData {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
buf.compose(self)
}
}
impl RecordData for UnknownRecordData {
fn rtype(&self) -> Rtype {
self.rtype
}
}
impl ParseRecordData for UnknownRecordData {
type Err = ShortBuf;
fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
-> Result<Option<Self>, Self::Err> {
parser.parse_bytes(rdlen)
.map(|data| Some(Self::from_bytes(rtype, data)))
}
}
impl fmt::Display for UnknownRecordData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\\# {}", self.data.len())?;
for ch in self.data.as_ref() {
write!(f, " {:02x}", *ch)?
}
Ok(())
}
}