use std::fmt;
use std::rc::Rc;
use ::bits::{DNameBuf, DNameSlice, RecordData};
use ::iana::{Class, Rtype};
use ::rdata::MasterRecordData;
use super::{ScanError, ScanResult, Scanner, SyntaxError};
#[derive(Clone, Debug)]
pub struct MasterRecord {
pub owner: Rc<DNameBuf>,
pub class: Class,
pub ttl: u32,
pub rdata: MasterRecordData,
}
impl MasterRecord {
pub fn new(owner: Rc<DNameBuf>, class: Class, ttl: u32,
rdata: MasterRecordData) -> Self {
MasterRecord { owner: owner, class: class,
ttl: ttl, rdata: rdata }
}
}
impl MasterRecord {
pub fn scan<S: Scanner>(stream: &mut S,
last_owner: Option<Rc<DNameBuf>>,
last_class: Option<Class>,
origin: &Option<Rc<DNameBuf>>,
default_ttl: Option<u32>) -> ScanResult<Self> {
let owner = try!(MasterRecord::scan_owner(stream, last_owner,
origin));
let (ttl, class) = try!(MasterRecord::scan_ttl_class(stream,
default_ttl,
last_class));
let rtype = try!(Rtype::scan(stream));
let rdata = try!(MasterRecordData::scan(rtype, stream,
map_origin(origin)));
try!(stream.scan_newline());
Ok(MasterRecord::new(owner, class, ttl, rdata))
}
fn scan_owner<S: Scanner>(stream: &mut S,
last_owner: Option<Rc<DNameBuf>>,
origin: &Option<Rc<DNameBuf>>)
-> ScanResult<Rc<DNameBuf>> {
let pos = stream.pos();
if let Ok(()) = stream.scan_space() {
if let Some(owner) = last_owner { Ok(owner) }
else { Err(ScanError::Syntax(SyntaxError::NoLastOwner, pos)) }
}
else if let Ok(()) = stream.skip_literal(b"@") {
if let Some(ref origin) = *origin { Ok(origin.clone()) }
else { Err(ScanError::Syntax(SyntaxError::NoOrigin, pos)) }
}
else {
Ok(Rc::new(try!(stream.scan_dname(map_origin(origin)))))
}
}
fn scan_ttl_class<S: Scanner>(stream: &mut S, default_ttl: Option<u32>,
last_class: Option<Class>)
-> ScanResult<(u32, Class)> {
let pos = stream.pos();
let (ttl, class) = match stream.scan_u32() {
Ok(ttl) => {
match Class::scan(stream) {
Ok(class) => {
(Some(ttl), Some(class))
}
Err(_) => (Some(ttl), None)
}
}
Err(_) => {
match Class::scan(stream) {
Ok(class) => {
match stream.scan_u32() {
Ok(ttl) => {
(Some(ttl), Some(class))
}
Err(_) => (None, Some(class))
}
}
Err(_) => (None, None)
}
}
};
let ttl = match ttl.or(default_ttl) {
Some(ttl) => ttl,
None => {
return Err(ScanError::Syntax(SyntaxError::NoDefaultTtl, pos))
}
};
let class = match class.or(last_class) {
Some(class) => class,
None => {
return Err(ScanError::Syntax(SyntaxError::NoLastClass, pos))
}
};
Ok((ttl, class))
}
}
impl fmt::Display for MasterRecord {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {} {} {}",
self.owner, self.ttl, self.class,
self.rdata.rtype(), self.rdata)
}
}
pub fn map_origin(origin: &Option<Rc<DNameBuf>>) -> Option<&DNameSlice> {
match *origin {
Some(ref rc) => Some(rc),
None => None
}
}