1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::collections::HashMap;
use std::num::{ParseFloatError, ParseIntError};
use std::str::ParseBoolError;

use chrono::{self, NaiveDate};
use xml::attribute::OwnedAttribute;
use xml::reader::{Error as ReaderError, Events, XmlEvent as ReaderEvent};

pub trait SVUEDecodeable {
    fn from_event(event: ReaderEvent, events_iter: &mut Events<&[u8]>)
        -> DecoderResult<Self> where Self: Sized;
}

pub type DecoderResult<T> = Result<T, DecodingError>;

#[derive(Debug)]
pub enum DecodingError {
    BoolParseError(String, ParseBoolError),
    DateParseError(String, chrono::ParseError),
    SVUEErrorParsingFailed(String),
    EventError(ReaderError),
    FloatParseError(String, ParseFloatError),
    IntegerParseError(String, ParseIntError),
    MissingAttribute(String),
    UnexpectedEnd,
    UnexpectedEvent(ReaderEvent),
}

#[inline]
pub fn parse_date(date: &str) -> Result<NaiveDate, chrono::ParseError>  {
    NaiveDate::parse_from_str(date, "%-m/%-d/%Y")
}

#[inline]
pub fn attributes_vec_to_map<'a>(attrs: &'a Vec<OwnedAttribute>) -> HashMap<&'a str, String> {
    attrs.iter()
        .map(|a| (a.name.local_name.as_str(), a.value.clone()))
        .fold(HashMap::new(), |mut acc, (k, v)| { acc.insert(k, v); acc })
}

#[macro_export]
macro_rules! get_attr {
    ( $attrs:expr, $attr:expr ) => {
        match $attrs.get($attr) {
            Some(val) => val,
            None => { return Err(DecodingError::MissingAttribute($attr.into())); }
        }
    };
}

#[macro_export]
macro_rules! get_attr_owned {
    ( $attrs:expr, $attr:expr ) => {
        get_attr!($attrs, $attr).clone()
    };
}

#[macro_export]
macro_rules! parse_date {
    ( $attrs:expr, $attr:expr ) => {
        {
            let date = parse_date(get_attr!($attrs, $attr));

            if date.is_err() {
                return Err(DecodingError::DateParseError($attr.into(), date.unwrap_err()));
            }

            date.unwrap()
        }
    };
}

#[macro_export]
macro_rules! parse_bool {
    ( $attrs:expr, $attr:expr ) => {
        {
            let b = bool::from_str(get_attr!($attrs, $attr));

            if b.is_err() {
                return Err(DecodingError::BoolParseError($attr.into(), b.unwrap_err()));
            }

            b.unwrap()
        }
    };
}

#[macro_export]
macro_rules! parse_int {
    ( $ity:tt, $attrs:expr, $attr:expr ) => {
        {
            let int = $ity::from_str_radix(get_attr!($attrs, $attr), 10);

            if int.is_err() {
                return Err(DecodingError::IntegerParseError($attr.into(), int.unwrap_err()));
            }

            int.unwrap()
        }
    };
}

#[macro_export]
macro_rules! parse_float {
    ( $fty:tt, $attrs:expr, $attr:expr ) => {
        {
            let f = $fty::from_str(get_attr!($attrs, $attr));

            if f.is_err() {
                return Err(DecodingError::FloatParseError($attr.into(), f.unwrap_err()));
            }

            f.unwrap()
        }
    };
}