pub mod accumulation;
pub mod filter;
pub mod iter;
pub mod spec;
use regex::Regex;
use std::fmt;
use std::result::Result as RResult;
use std::str::FromStr;
use error::*;
use error::ErrorKind as EK;
#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
pub struct TrailerKey(String);
impl From<String> for TrailerKey {
fn from(string: String) -> Self {
TrailerKey(string)
}
}
impl AsRef<String> for TrailerKey {
fn as_ref(&self) -> &String {
&self.0
}
}
impl fmt::Display for TrailerKey {
fn fmt(&self, f: &mut fmt::Formatter) -> RResult<(), fmt::Error> {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
pub enum TrailerValue {
Int(i64),
String(String),
}
impl TrailerValue {
pub fn from_slice(slice: &str) -> TrailerValue {
match i64::from_str(slice) {
Ok(i) => TrailerValue::Int(i),
Err(_) => TrailerValue::String(String::from(slice)),
}
}
pub fn append(&mut self, slice: &str) {
match self {
&mut TrailerValue::Int(i) => *self = TrailerValue::String(i.to_string() + slice),
&mut TrailerValue::String(ref mut s) => s.push_str(slice),
}
}
}
impl Default for TrailerValue {
fn default() -> Self {
TrailerValue::String(String::new())
}
}
impl fmt::Display for TrailerValue {
fn fmt(&self, f: &mut fmt::Formatter) -> RResult<(), fmt::Error> {
match *self {
TrailerValue::Int(i) => write!(f, "{}", i),
TrailerValue::String(ref s) => write!(f, "{}", s),
}
}
}
#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone)]
pub struct Trailer {
pub key: TrailerKey,
pub value: TrailerValue,
}
impl Trailer {
pub fn new(key: &str, value: &str) -> Trailer {
Trailer {
key : TrailerKey::from(String::from(key)),
value: TrailerValue::from_slice(value),
}
}
}
impl Into<(TrailerKey, TrailerValue)> for Trailer {
fn into(self) -> (TrailerKey, TrailerValue) {
(self.key, self.value)
}
}
impl fmt::Display for Trailer {
fn fmt(&self, f: &mut fmt::Formatter) -> RResult<(), fmt::Error> {
write!(f, "{}: {}", self.key, self.value)
}
}
impl FromStr for Trailer {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^([[:alnum:]-]+)[:=](.*)$").unwrap();
}
match RE.captures(s).map(|c| (c.get(1), c.get(2))) {
Some((Some(key), Some(value))) => Ok(Trailer::new(key.as_str(), value.as_str().trim())),
_ => Err(Error::from_kind(EK::TrailerFormatError(s.to_owned())))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn string_trailer() {
let (key, value) = Trailer::from_str("foo-bar: test1 test2 test3")
.expect("Couldn't parse test string")
.into();
assert_eq!(key, TrailerKey("foo-bar".to_string()));
assert_eq!(value, TrailerValue::String("test1 test2 test3".to_string()));
}
#[test]
fn string_numstart_trailer() {
let (key, value) = Trailer::from_str("foo-bar: 123test")
.expect("Couldn't parse test string")
.into();
assert_eq!(key, TrailerKey("foo-bar".to_string()));
assert_eq!(value, TrailerValue::String("123test".to_string()));
}
#[test]
fn numeric_trailer() {
let (key, value) = Trailer::from_str("foo-bar: 123")
.expect("Couldn't parse test string")
.into();
assert_eq!(key, TrailerKey("foo-bar".to_string()));
assert_eq!(value, TrailerValue::Int(123));
}
#[test]
fn faulty_trailer() {
assert!(Trailer::from_str("foo-bar 123").is_err());
}
#[test]
fn faulty_trailer_2() {
assert!(Trailer::from_str("foo-bar").is_err());
}
#[test]
fn faulty_trailer_3() {
assert!(Trailer::from_str("foo bar: baz").is_err());
}
#[test]
fn empty_trailer() {
assert!(Trailer::from_str("").is_err());
}
}