use std::fmt; mod std_impls; pub mod quoted; pub fn skip_whitespace(data: &mut &str) { *data = (*data).trim_left(); } pub fn next_field<'a>(data: &mut &'a str) -> ::errors::Result<&'a str> { *data = (*data).trim_left(); if data.is_empty() { bail!("missing field"); } match data.find(char::is_whitespace) { None => { let result = *data; *data = ""; Ok(result) }, Some(next) => { let result = &(*data)[..next]; *data = &(*data)[next..].trim_left(); Ok(result) }, } } pub fn next_quoted_field(data: &mut &str) -> ::errors::Result> { *data = (*data).trim_left(); if data.is_empty() { bail!("missing field"); } let result = quoted::UnquoteIterator::new(data).collect::, _>>()?; Ok(result) } pub fn quote(data: &[u8]) -> String { let mut result = String::with_capacity(data.len() + 2); result.push('"'); for qc in quoted::EncodeIterator::new_quoted(data) { result += &qc; } result.push('"'); result } // also escapes whitespace, but doesn't use quotes to surround it pub fn escape(data: &[u8]) -> String { let mut result = String::with_capacity(data.len()); for qc in quoted::EncodeIterator::new_encode_whitespace(data) { result += &qc; } result } /// Each call to write!() makes sure a space is emitted to separate it /// from previous fields. pub struct DnsTextFormatter<'a> { f: &'a mut fmt::Formatter<'a>, need_space: bool, } impl<'a> DnsTextFormatter<'a> { pub fn new(f: &'a mut fmt::Formatter<'a>) -> Self { DnsTextFormatter { f: f, need_space: false, } } /// make sure a field separator was emitted pub fn next_field(&mut self) -> fmt::Result { if self.need_space { write!(self.f, " ")?; self.need_space = false; } Ok(()) } /// a field was emitted through `inner`; next field needs a separator pub fn end_field(&mut self) { self.need_space = true; } /// direct access to underlying output; you'll need to call /// `next_field` and `end_field` manually. pub fn inner(&mut self) -> &mut fmt::Formatter<'a> { self.f } pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { self.next_field()?; self.f.write_fmt(args)?; self.end_field(); Ok(()) } } pub trait DnsTextData { fn dns_parse(data: &mut &str) -> ::errors::Result where Self: Sized, ; // format might fail if there is no (known) text representation. fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result; } pub fn parse(data: &str) -> ::errors::Result where T: DnsTextData { let mut data = data; let result = T::dns_parse(&mut data)?; let data = data.trim(); ensure!(data.is_empty(), "didn't parse complete text, remaining: {:?}", data); Ok(result) }