rust-dnsbox/lib/dnsbox-base/src/ser/text/mod.rs

116 lines
2.6 KiB
Rust

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<Vec<u8>> {
*data = (*data).trim_left();
if data.is_empty() { bail!("missing field"); }
let result = quoted::UnquoteIterator::new(data).collect::<Result<Vec<_>, _>>()?;
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<Self>
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<T>(data: &str) -> ::errors::Result<T>
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)
}