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
117
118
119
120
121
122
123
124
125
use ion::Value;

pub trait FromIon<T>: Sized {
    type Err;
    fn from_ion(&T) -> Result<Self, Self::Err>;
}

impl FromIon<Value> for String {
    type Err = ();
    fn from_ion(value: &Value) -> Result<Self, Self::Err> {
        value.as_string().map(|s| s.to_owned()).ok_or(())
    }
}

impl FromIon<Value> for Option<String> {
    type Err = ();
    fn from_ion(value: &Value) -> Result<Self, Self::Err> {
        value.as_string()
            .map(|s| if s.is_empty() {
                None
            } else {
                Some(s.to_owned())
            })
            .ok_or(())
    }
}

macro_rules! from_ion_value_int_impl {
     ($($t:ty)*) => {$(
         impl FromIon<Value> for $t {
             type Err = ::std::num::ParseIntError;
             fn from_ion(value: &Value) -> Result<Self, Self::Err> {
                match value.as_string() {
                    Some(s) => Ok(s.parse()?),
                    None => "".parse()
                }
             }
         }
     )*}
 }

from_ion_value_int_impl!{ isize i8 i16 i32 i64 usize u8 u16 u32 u64 }

impl FromIon<Value> for bool {
    type Err = ::std::str::ParseBoolError;
    fn from_ion(value: &Value) -> Result<Self, Self::Err> {
        match value.as_string() {
            Some(s) => Ok(s.parse()?),
            None => "".parse(),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use ion::{FromIon, Section, Value};

    #[test]
    fn string() {
        let v = Value::String("foo".to_owned());
        let s = String::from_ion(&v).unwrap();
        assert_eq!("foo", s);
        let s: String = v.from_ion().unwrap();
        assert_eq!("foo", s);
    }

    #[test]
    fn option_string() {
        let v = Value::from_str("foo").unwrap();
        let os: Option<String> = v.from_ion().unwrap();
        assert_eq!(Some("foo".to_owned()), os);

        let v = Value::from_str("").unwrap();
        let os: Option<String> = v.from_ion().unwrap();
        assert_eq!(None, os);
    }

    #[test]
    fn u32() {
        let v = Value::from_str("16").unwrap();
        let u: u32 = v.from_ion().unwrap();
        assert_eq!(16, u);
    }

    #[test]
    fn bool() {
        let v = Value::from_str("true").unwrap();
        let u: bool = v.from_ion().unwrap();
        assert_eq!(true, u);

        let v = Value::from_str("false").unwrap();
        let u: bool = v.from_ion().unwrap();
        assert_eq!(false, u);

        let v = Value::from_str("").unwrap();
        let u: Result<bool, _> = v.from_ion();
        assert!(u.is_err());

    }

    struct Foo {
        a: u32,
        b: String,
    }


    impl FromIon<Section> for Foo {
        type Err = ();
        fn from_ion(_section: &Section) -> Result<Self, Self::Err> {
            Ok(Foo {
                a: 1,
                b: "foo".to_owned(),
            })
        }
    }

    #[test]
    fn from_ion_section() {
        let section = Section::new();
        let foo: Foo = section.parse().unwrap();
        assert_eq!(1, foo.a);
        assert_eq!("foo", foo.b);
    }
}