diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-04-02 17:04:17 -0700 | 
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-04-02 17:07:37 -0700 | 
| commit | 2d49247b92f74cf760202b7d1a08d61804f45bca (patch) | |
| tree | e000d46eeda80b4cee5e5ac79a36f00970ca4a6a | |
| parent | cd33b87bf9a7f1e08fc73c436db51def4850855a (diff) | |
| download | milf-rs-2d49247b92f74cf760202b7d1a08d61804f45bca.tar.gz milf-rs-2d49247b92f74cf760202b7d1a08d61804f45bca.zip  | |
Modularize rustc-serialize support
* Add rustc-serialize as a default feature
* Make room for for serde support
| -rw-r--r-- | .travis.yml | 2 | ||||
| -rw-r--r-- | Cargo.toml | 8 | ||||
| -rw-r--r-- | src/decoder/mod.rs | 205 | ||||
| -rw-r--r-- | src/decoder/rustc_serialize.rs | 311 | ||||
| -rw-r--r-- | src/encoder/mod.rs | 210 | ||||
| -rw-r--r-- | src/encoder/rustc_serialize.rs | 689 | ||||
| -rw-r--r-- | src/lib.rs | 70 | ||||
| -rw-r--r-- | src/serialization.rs | 1279 | 
8 files changed, 1434 insertions, 1340 deletions
diff --git a/.travis.yml b/.travis.yml index 41b485d..145528e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,9 @@ language: rust  sudo: false  script:    - cargo build --verbose +  - cargo build --verbose --no-default-features    - cargo test --verbose +  - cargo test --verbose --no-default-features    - rustdoc --test README.md -L target    - cargo doc --no-deps  after_success: | @@ -16,4 +16,10 @@ facilitate deserializing and serializing Rust structures.  """  [dependencies] -rustc-serialize = "0.3.0" +rustc-serialize = { optional = true, version = "0.3.0" } + +[features] +default = ["rustc-serialize"] + +[dev-dependencies] +rustc-serialize = "0.3" diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs new file mode 100644 index 0000000..675e0ca --- /dev/null +++ b/src/decoder/mod.rs @@ -0,0 +1,205 @@ +use std::error; +use std::fmt; + +use Value; +use self::DecodeErrorKind::*; + +#[cfg(feature = "rustc-serialize")] mod rustc_serialize; + +/// A structure to transform TOML values into Rust values. +/// +/// This decoder implements the serialization `Decoder` interface, allowing +/// `Decodable` types to be generated by this decoder. The input is any +/// arbitrary TOML value. +pub struct Decoder { +    /// The TOML value left over after decoding. This can be used to inspect +    /// whether fields were decoded or not. +    pub toml: Option<Value>, +    cur_field: Option<String>, +} + +/// Description for errors which can occur while decoding a type. +#[derive(PartialEq, Debug)] +pub struct DecodeError { +    /// Field that this error applies to. +    pub field: Option<String>, +    /// The type of error which occurred while decoding, +    pub kind: DecodeErrorKind, +} + +/// Enumeration of possible errors which can occur while decoding a structure. +#[derive(PartialEq, Debug)] +pub enum DecodeErrorKind { +    /// An error flagged by the application, e.g. value out of range +    ApplicationError(String), +    /// A field was expected, but none was found. +    ExpectedField(/* type */ Option<&'static str>), +    /// A field was found, but it had the wrong type. +    ExpectedType(/* expected */ &'static str, /* found */ &'static str), +    /// The nth map key was expected, but none was found. +    ExpectedMapKey(usize), +    /// The nth map element was expected, but none was found. +    ExpectedMapElement(usize), +    /// An enum decoding was requested, but no variants were supplied +    NoEnumVariants, +    /// The unit type was being decoded, but a non-zero length string was found +    NilTooLong, +    /// There was an error with the syntactical structure of the TOML. +    SyntaxError, +    /// The end of the TOML input was reached too soon +    EndOfStream, +} + +/// Decodes a TOML value into a decodable type. +/// +/// This function will consume the given TOML value and attempt to decode it +/// into the type specified. If decoding fails, `None` will be returned. If a +/// finer-grained error is desired, then it is recommended to use `Decodable` +/// directly. +#[cfg(feature = "rustc-serialize")] +pub fn decode<T: ::rustc_serialize::Decodable>(toml: Value) -> Option<T> { +    ::rustc_serialize::Decodable::decode(&mut Decoder::new(toml)).ok() +} + +/// Decodes a TOML value into a decodable type. +/// +/// This function will consume the given TOML value and attempt to decode it +/// into the type specified. If decoding fails, `None` will be returned. If a +/// finer-grained error is desired, then it is recommended to use `Decodable` +/// directly. +#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))] +pub fn decode<T: ::serde::Deserialize>(toml: Value) -> Option<T> { +    ::serde::Deserialize::deserialize(&mut Decoder::new(toml)).ok() +} + +/// Decodes a string into a toml-encoded value. +/// +/// This function will parse the given string into a TOML value, and then parse +/// the TOML value into the desired type. If any error occurs `None` is return. +/// +/// If more fine-grained errors are desired, these steps should be driven +/// manually. +#[cfg(feature = "rustc-serialize")] +pub fn decode_str<T: ::rustc_serialize::Decodable>(s: &str) -> Option<T> { +    ::Parser::new(s).parse().and_then(|t| decode(Value::Table(t))) +} + +/// Decodes a string into a toml-encoded value. +/// +/// This function will parse the given string into a TOML value, and then parse +/// the TOML value into the desired type. If any error occurs `None` is return. +/// +/// If more fine-grained errors are desired, these steps should be driven +/// manually. +#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))] +pub fn decode_str<T: ::serde::Deserialize>(s: &str) -> Option<T> { +    ::Parser::new(s).parse().and_then(|t| decode(Value::Table(t))) +} + +impl Decoder { +    /// Creates a new decoder, consuming the TOML value to decode. +    /// +    /// This decoder can be passed to the `Decodable` methods or driven +    /// manually. +    pub fn new(toml: Value) -> Decoder { +        Decoder { toml: Some(toml), cur_field: None } +    } + +    fn sub_decoder(&self, toml: Option<Value>, field: &str) -> Decoder { +        Decoder { +            toml: toml, +            cur_field: if field.len() == 0 { +                self.cur_field.clone() +            } else { +                match self.cur_field { +                    None => Some(format!("{}", field)), +                    Some(ref s) => Some(format!("{}.{}", s, field)) +                } +            } +        } +    } + +    fn err(&self, kind: DecodeErrorKind) -> DecodeError { +        DecodeError { +            field: self.cur_field.clone(), +            kind: kind, +        } +    } + +    fn mismatch(&self, expected: &'static str, +                found: &Option<Value>) -> DecodeError{ +        match *found { +            Some(ref val) => self.err(ExpectedType(expected, val.type_str())), +            None => self.err(ExpectedField(Some(expected))), +        } +    } +} + +impl fmt::Display for DecodeError { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        try!(match self.kind { +            ApplicationError(ref err) => { +                write!(f, "{}", err) +            } +            ExpectedField(expected_type) => { +                match expected_type { +                    Some("table") => write!(f, "expected a section"), +                    Some(e) => write!(f, "expected a value of type `{}`", e), +                    None => write!(f, "expected a value"), +                } +            } +            ExpectedType(expected, found) => { +                fn humanize(s: &str) -> String { +                    if s == "section" { +                        format!("a section") +                    } else { +                        format!("a value of type `{}`", s) +                    } +                } +                write!(f, "expected {}, but found {}", +                       humanize(expected), +                       humanize(found)) +            } +            ExpectedMapKey(idx) => { +                write!(f, "expected at least {} keys", idx + 1) +            } +            ExpectedMapElement(idx) => { +                write!(f, "expected at least {} elements", idx + 1) +            } +            NoEnumVariants => { +                write!(f, "expected an enum variant to decode to") +            } +            NilTooLong => { +                write!(f, "expected 0-length string") +            } +            SyntaxError => { +                write!(f, "syntax error") +            } +            EndOfStream => { +                write!(f, "end of stream") +            } +        }); +        match self.field { +            Some(ref s) => { +                write!(f, " for the key `{}`", s) +            } +            None => Ok(()) +        } +    } +} + +impl error::Error for DecodeError { +    fn description(&self) -> &str { +        match self.kind { +            ApplicationError(ref s) => &**s, +            ExpectedField(..) => "expected a field", +            ExpectedType(..) => "expected a type", +            ExpectedMapKey(..) => "expected a map key", +            ExpectedMapElement(..) => "expected a map element", +            NoEnumVariants => "no enum variants to decode to", +            NilTooLong => "nonzero length string representing nil", +            SyntaxError => "syntax error", +            EndOfStream => "end of stream", +        } +    } +} diff --git a/src/decoder/rustc_serialize.rs b/src/decoder/rustc_serialize.rs new file mode 100644 index 0000000..6e8fe59 --- /dev/null +++ b/src/decoder/rustc_serialize.rs @@ -0,0 +1,311 @@ +use rustc_serialize; +use std::mem; + +use super::{Decoder, DecodeError}; +use super::DecodeErrorKind::*; +use Value; + +impl rustc_serialize::Decoder for Decoder { +    type Error = DecodeError; +    fn read_nil(&mut self) -> Result<(), DecodeError> { +        match self.toml { +            Some(Value::String(ref s)) if s.len() == 0 => {} +            Some(Value::String(..)) => return Err(self.err(NilTooLong)), +            ref found => return Err(self.mismatch("string", found)), +        } +        self.toml.take(); +        Ok(()) +    } +    fn read_usize(&mut self) -> Result<usize, DecodeError> { +        self.read_i64().map(|i| i as usize) +    } +    fn read_u64(&mut self) -> Result<u64, DecodeError> { +        self.read_i64().map(|i| i as u64) +    } +    fn read_u32(&mut self) -> Result<u32, DecodeError> { +        self.read_i64().map(|i| i as u32) +    } +    fn read_u16(&mut self) -> Result<u16, DecodeError> { +        self.read_i64().map(|i| i as u16) +    } +    fn read_u8(&mut self) -> Result<u8, DecodeError> { +        self.read_i64().map(|i| i as u8) +    } +    fn read_isize(&mut self) -> Result<isize, DecodeError> { +        self.read_i64().map(|i| i as isize) +    } +    fn read_i64(&mut self) -> Result<i64, DecodeError> { +        match self.toml { +            Some(Value::Integer(i)) => { self.toml.take(); Ok(i) } +            ref found => Err(self.mismatch("integer", found)), +        } +    } +    fn read_i32(&mut self) -> Result<i32, DecodeError> { +        self.read_i64().map(|i| i as i32) +    } +    fn read_i16(&mut self) -> Result<i16, DecodeError> { +        self.read_i64().map(|i| i as i16) +    } +    fn read_i8(&mut self) -> Result<i8, DecodeError> { +        self.read_i64().map(|i| i as i8) +    } +    fn read_bool(&mut self) -> Result<bool, DecodeError> { +        match self.toml { +            Some(Value::Boolean(b)) => { self.toml.take(); Ok(b) } +            ref found => Err(self.mismatch("bool", found)), +        } +    } +    fn read_f64(&mut self) -> Result<f64, DecodeError> { +        match self.toml { +            Some(Value::Float(f)) => Ok(f), +            ref found => Err(self.mismatch("float", found)), +        } +    } +    fn read_f32(&mut self) -> Result<f32, DecodeError> { +        self.read_f64().map(|f| f as f32) +    } +    fn read_char(&mut self) -> Result<char, DecodeError> { +        let ch = match self.toml { +            Some(Value::String(ref s)) if s.chars().count() == 1 => +                s.chars().next().unwrap(), +            ref found => return Err(self.mismatch("string", found)), +        }; +        self.toml.take(); +        Ok(ch) +    } +    fn read_str(&mut self) -> Result<String, DecodeError> { +        match self.toml.take() { +            Some(Value::String(s)) => Ok(s), +            found => { +                let err = Err(self.mismatch("string", &found)); +                self.toml = found; +                err +            } +        } +    } + +    // Compound types: +    fn read_enum<T, F>(&mut self, _name: &str, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        f(self) +    } + +    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) +        -> Result<T, DecodeError> +        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError> +    { +        let mut first_error = None; +        for i in 0..names.len() { +            let mut d = self.sub_decoder(self.toml.clone(), ""); +            match f(&mut d, i) { +                Ok(t) => { self.toml = d.toml; return Ok(t) } +                Err(e) => { +                    if first_error.is_none() { +                        first_error = Some(e); +                    } +                } +            } +        } +        Err(first_error.unwrap_or_else(|| self.err(NoEnumVariants))) +    } +    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        f(self) +    } + +    fn read_enum_struct_variant<T, F>(&mut self, _names: &[&str], _f: F) +        -> Result<T, DecodeError> +        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError> +    { +        panic!() +    } +    fn read_enum_struct_variant_field<T, F>(&mut self, +                                            _f_name: &str, +                                            _f_idx: usize, +                                            _f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        panic!() +    } + +    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        match self.toml { +            Some(Value::Table(..)) => { +                let ret = try!(f(self)); +                match self.toml { +                    Some(Value::Table(ref t)) if t.len() == 0 => {} +                    _ => return Ok(ret) +                } +                self.toml.take(); +                Ok(ret) +            } +            ref found => Err(self.mismatch("table", found)), +        } +    } +    fn read_struct_field<T, F>(&mut self, f_name: &str, _f_idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        let field = format!("{}", f_name); +        let toml = match self.toml { +            Some(Value::Table(ref mut table)) => { +                table.remove(&field) +                    .or_else(|| table.remove(&f_name.replace("_", "-"))) +            }, +            ref found => return Err(self.mismatch("table", found)), +        }; +        let mut d = self.sub_decoder(toml, f_name); +        let ret = try!(f(&mut d)); +        if let Some(value) = d.toml { +            if let Some(Value::Table(ref mut table)) = self.toml { +                table.insert(field, value); +            } +        } +        Ok(ret) +    } + +    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        self.read_seq(move |d, len| { +            assert!(len == tuple_len, +                    "expected tuple of length `{}`, found tuple \ +                         of length `{}`", tuple_len, len); +            f(d) +        }) +    } +    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        self.read_seq_elt(a_idx, f) +    } + +    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, _len: usize, _f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        panic!() +    } +    fn read_tuple_struct_arg<T, F>(&mut self, _a_idx: usize, _f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        panic!() +    } + +    // Specialized types: +    fn read_option<T, F>(&mut self, mut f: F) +        -> Result<T, DecodeError> +        where F: FnMut(&mut Decoder, bool) -> Result<T, DecodeError> +    { +        match self.toml { +            Some(..) => f(self, true), +            None => f(self, false), +        } +    } + +    fn read_seq<T, F>(&mut self, f: F) -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError> +    { +        let len = match self.toml { +            Some(Value::Array(ref arr)) => arr.len(), +            None => 0, +            ref found => return Err(self.mismatch("array", found)), +        }; +        let ret = try!(f(self, len)); +        match self.toml { +            Some(Value::Array(ref mut arr)) => { +                arr.retain(|slot| slot.as_integer() != Some(0)); +                if arr.len() != 0 { return Ok(ret) } +            } +            _ => return Ok(ret) +        } +        self.toml.take(); +        Ok(ret) +    } +    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        let toml = match self.toml { +            Some(Value::Array(ref mut arr)) => { +                mem::replace(&mut arr[idx], Value::Integer(0)) +            } +            ref found => return Err(self.mismatch("array", found)), +        }; +        let mut d = self.sub_decoder(Some(toml), ""); +        let ret = try!(f(&mut d)); +        match d.toml { +            Some(toml) => match self.toml { +                Some(Value::Array(ref mut arr)) => arr[idx] = toml, +                _ => {} +            }, +            _ => {} +        } +        Ok(ret) +    } + +    fn read_map<T, F>(&mut self, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError> +    { +        let len = match self.toml { +            Some(Value::Table(ref table)) => table.len(), +            ref found => return Err(self.mismatch("table", found)), +        }; +        let ret = try!(f(self, len)); +        self.toml.take(); +        Ok(ret) +    } +    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        match self.toml { +            Some(Value::Table(ref table)) => { +                match table.iter().skip(idx).next() { +                    Some((key, _)) => { +                        let val = Value::String(format!("{}", key)); +                        f(&mut self.sub_decoder(Some(val), &**key)) +                    } +                    None => Err(self.err(ExpectedMapKey(idx))), +                } +            } +            ref found => Err(self.mismatch("table", found)), +        } +    } +    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) +        -> Result<T, DecodeError> +        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> +    { +        match self.toml { +            Some(Value::Table(ref table)) => { +                match table.iter().skip(idx).next() { +                    Some((_, value)) => { +                        // XXX: this shouldn't clone +                        f(&mut self.sub_decoder(Some(value.clone()), "")) +                    } +                    None => Err(self.err(ExpectedMapElement(idx))), +                } +            } +            ref found => Err(self.mismatch("table", found)), +        } +    } + +    fn error(&mut self, err: &str) -> DecodeError { +        DecodeError { +            field: self.cur_field.clone(), +            kind: ApplicationError(format!("{}", err)) +        } +    } +} diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs new file mode 100644 index 0000000..21185f4 --- /dev/null +++ b/src/encoder/mod.rs @@ -0,0 +1,210 @@ +use std::collections::BTreeMap; +use std::error; +use std::fmt; +use std::mem; + +use {Value, Table}; + +#[cfg(feature = "rustc-serialize")] mod rustc_serialize; + +/// A structure to transform Rust values into TOML values. +/// +/// This encoder implements the serialization `Encoder` interface, allowing +/// `Encodable` rust types to be fed into the encoder. The output of this +/// encoder is a TOML `Table` structure. The resulting TOML can be stringified +/// if necessary. +/// +/// # Example +/// +/// ``` +/// extern crate rustc_serialize; +/// extern crate toml; +/// +/// # fn main() { +/// use toml::{Encoder, Value}; +/// use rustc_serialize::Encodable; +/// +/// #[derive(RustcEncodable)] +/// struct MyStruct { foo: isize, bar: String } +/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() }; +/// +/// let mut e = Encoder::new(); +/// my_struct.encode(&mut e).unwrap(); +/// +/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4))) +/// # } +/// ``` +pub struct Encoder { +    /// Output TOML that is emitted. The current version of this encoder forces +    /// the top-level representation of a structure to be a table. +    /// +    /// This field can be used to extract the return value after feeding a value +    /// into this `Encoder`. +    pub toml: Table, +    state: State, +} + +/// Enumeration of errors which can occur while encoding a rust value into a +/// TOML value. +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub enum Error { +    /// Indication that a key was needed when a value was emitted, but no key +    /// was previously emitted. +    NeedsKey, +    /// Indication that a key was emitted, but not value was emitted. +    NoValue, +    /// Indicates that a map key was attempted to be emitted at an invalid +    /// location. +    InvalidMapKeyLocation, +    /// Indicates that a type other than a string was attempted to be used as a +    /// map key type. +    InvalidMapKeyType, +} + +#[derive(PartialEq)] +enum State { +    Start, +    NextKey(String), +    NextArray(Vec<Value>), +    NextMapKey, +} + +impl Encoder { +    /// Constructs a new encoder which will emit to the given output stream. +    pub fn new() -> Encoder { +        Encoder { state: State::Start, toml: BTreeMap::new() } +    } + +    fn emit_value(&mut self, v: Value) -> Result<(), Error> { +        match mem::replace(&mut self.state, State::Start) { +            State::NextKey(key) => { self.toml.insert(key, v); Ok(()) } +            State::NextArray(mut vec) => { +                // TODO: validate types +                vec.push(v); +                self.state = State::NextArray(vec); +                Ok(()) +            } +            State::NextMapKey => { +                match v { +                    Value::String(s) => { self.state = State::NextKey(s); Ok(()) } +                    _ => Err(Error::InvalidMapKeyType) +                } +            } +            _ => Err(Error::NeedsKey) +        } +    } + +    fn emit_none(&mut self) -> Result<(), Error> { +        match mem::replace(&mut self.state, State::Start) { +            State::Start => unreachable!(), +            State::NextKey(_) => Ok(()), +            State::NextArray(..) => panic!("how to encode None in an array?"), +            State::NextMapKey => Err(Error::InvalidMapKeyLocation), +        } +    } + +    fn seq<F>(&mut self, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        let old = mem::replace(&mut self.state, State::NextArray(Vec::new())); +        try!(f(self)); +        match mem::replace(&mut self.state, old) { +            State::NextArray(v) => self.emit_value(Value::Array(v)), +            _ => unreachable!(), +        } +    } + +    fn table<F>(&mut self, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        match mem::replace(&mut self.state, State::Start) { +            State::NextKey(key) => { +                let mut nested = Encoder::new(); +                try!(f(&mut nested)); +                self.toml.insert(key, Value::Table(nested.toml)); +                Ok(()) +            } +            State::NextArray(mut arr) => { +                let mut nested = Encoder::new(); +                try!(f(&mut nested)); +                arr.push(Value::Table(nested.toml)); +                self.state = State::NextArray(arr); +                Ok(()) +            } +            State::Start => f(self), +            State::NextMapKey => Err(Error::InvalidMapKeyLocation), +        } +    } + +    fn table_key<F>(&mut self, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        match mem::replace(&mut self.state, State::NextMapKey) { +            State::Start => {} +            _ => return Err(Error::InvalidMapKeyLocation), +        } +        try!(f(self)); +        match self.state { +            State::NextKey(_) => Ok(()), +            _ => Err(Error::InvalidMapKeyLocation), +        } +    } +} + +/// Encodes an encodable value into a TOML value. +/// +/// This function expects the type given to represent a TOML table in some form. +/// If encoding encounters an error, then this function will fail the task. +#[cfg(feature = "rustc-serialize")] +pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value { +    let mut e = Encoder::new(); +    t.encode(&mut e).unwrap(); +    Value::Table(e.toml) +} + +/// Encodes an encodable value into a TOML value. +/// +/// This function expects the type given to represent a TOML table in some form. +/// If encoding encounters an error, then this function will fail the task. +#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))] +pub fn encode<T: ::serde::Serialize>(t: &T) -> Value { +    let mut e = Encoder::new(); +    t.deserialize(&mut e).unwrap(); +    Value::Table(e.toml) +} + +/// Encodes an encodable value into a TOML string. +/// +/// This function expects the type given to represent a TOML table in some form. +/// If encoding encounters an error, then this function will fail the task. +#[cfg(feature = "rustc-serialize")] +pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String { +    encode(t).to_string() +} + +/// Encodes an encodable value into a TOML string. +/// +/// This function expects the type given to represent a TOML table in some form. +/// If encoding encounters an error, then this function will fail the task. +#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))] +pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String { +    encode(t).to_string() +} + +impl fmt::Display for Error { +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        match *self { +            Error::NeedsKey => write!(f, "need a key to encode"), +            Error::NoValue => write!(f, "not value to emit for a previous key"), +            Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \ +                                                       at this location"), +            Error::InvalidMapKeyType => write!(f, "only strings can be used as \ +                                                   key types"), +        } +    } +} + +impl error::Error for Error { +    fn description(&self) -> &str { "TOML encoding error" } +} diff --git a/src/encoder/rustc_serialize.rs b/src/encoder/rustc_serialize.rs new file mode 100644 index 0000000..ab5e90f --- /dev/null +++ b/src/encoder/rustc_serialize.rs @@ -0,0 +1,689 @@ +use std::mem; + +use rustc_serialize; +use Value; +use super::{Encoder, Error, State}; +use super::Error::*; + +impl rustc_serialize::Encoder for Encoder { +    type Error = Error; + +    fn emit_nil(&mut self) -> Result<(), Error> { Ok(()) } +    fn emit_usize(&mut self, v: usize) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_u8(&mut self, v: u8) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_u16(&mut self, v: u16) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_u32(&mut self, v: u32) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_u64(&mut self, v: u64) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_isize(&mut self, v: isize) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_i8(&mut self, v: i8) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_i16(&mut self, v: i16) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_i32(&mut self, v: i32) -> Result<(), Error> { +        self.emit_i64(v as i64) +    } +    fn emit_i64(&mut self, v: i64) -> Result<(), Error> { +        self.emit_value(Value::Integer(v)) +    } +    fn emit_bool(&mut self, v: bool) -> Result<(), Error> { +        self.emit_value(Value::Boolean(v)) +    } +    fn emit_f32(&mut self, v: f32) -> Result<(), Error> { self.emit_f64(v as f64) } +    fn emit_f64(&mut self, v: f64) -> Result<(), Error> { +        self.emit_value(Value::Float(v)) +    } +    fn emit_char(&mut self, v: char) -> Result<(), Error> { +        self.emit_str(&*format!("{}", v)) +    } +    fn emit_str(&mut self, v: &str) -> Result<(), Error> { +        self.emit_value(Value::String(format!("{}", v))) +    } +    fn emit_enum<F>(&mut self, _name: &str, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, +                            _len: usize, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, +                                   _len: usize, +                                   _f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        panic!() +    } +    fn emit_enum_struct_variant_field<F>(&mut self, +                                         _f_name: &str, +                                         _f_idx: usize, +                                         _f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        panic!() +    } +    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.table(f) +    } +    fn emit_struct_field<F>(&mut self, f_name: &str, _f_idx: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        let old = mem::replace(&mut self.state, +                               State::NextKey(format!("{}", f_name))); +        try!(f(self)); +        if self.state != State::Start { +            return Err(NoValue) +        } +        self.state = old; +        Ok(()) +    } +    fn emit_tuple<F>(&mut self, len: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.emit_seq(len, f) +    } +    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.emit_seq_elt(idx, f) +    } +    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, _f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        unimplemented!() +    } +    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, _f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        unimplemented!() +    } +    fn emit_option<F>(&mut self, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_option_none(&mut self) -> Result<(), Error> { +        self.emit_none() +    } +    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_seq<F>(&mut self, _len: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.seq(f) +    } +    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +    fn emit_map<F>(&mut self, len: usize, f: F) +        -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.emit_struct("foo", len, f) +    } +    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        self.table_key(f) +    } +    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Error> +        where F: FnOnce(&mut Encoder) -> Result<(), Error> +    { +        f(self) +    } +} + +impl rustc_serialize::Encodable for Value { +    fn encode<E>(&self, e: &mut E) -> Result<(), E::Error> +        where E: rustc_serialize::Encoder +    { +        match *self { +            Value::String(ref s) => e.emit_str(s), +            Value::Integer(i) => e.emit_i64(i), +            Value::Float(f) => e.emit_f64(f), +            Value::Boolean(b) => e.emit_bool(b), +            Value::Datetime(ref s) => e.emit_str(s), +            Value::Array(ref a) => { +                e.emit_seq(a.len(), |e| { +                    for item in a { +                        try!(item.encode(e)); +                    } +                    Ok(()) +                }) +            } +            Value::Table(ref t) => { +                e.emit_map(t.len(), |e| { +                    for (i, (key, value)) in t.iter().enumerate() { +                        try!(e.emit_map_elt_key(i, |e| e.emit_str(key))); +                        try!(e.emit_map_elt_val(i, |e| value.encode(e))); +                    } +                    Ok(()) +                }) +            } +        } +    } +} + +#[cfg(test)] +mod tests { +    use std::collections::{BTreeMap, HashSet}; +    use rustc_serialize::{self, Encodable, Decodable}; + +    use {Encoder, Decoder, DecodeError}; +    use Value; +    use Value::{Table, Integer, Array, Float}; + +    macro_rules! encode( ($t:expr) => ({ +        let mut e = Encoder::new(); +        $t.encode(&mut e).unwrap(); +        e.toml +    }) ); + +    macro_rules! decode( ($t:expr) => ({ +        let mut d = Decoder::new($t); +        Decodable::decode(&mut d).unwrap() +    }) ); + +    macro_rules! map( ($($k:ident, $v:expr),*) => ({ +        let mut _m = BTreeMap::new(); +        $(_m.insert(stringify!($k).to_string(), $v);)* +        _m +    }) ); + +    #[test] +    fn smoke() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: isize } + +        let v = Foo { a: 2 }; +        assert_eq!(encode!(v), map! { a, Integer(2) }); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn smoke_hyphen() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a_b: isize } + +        let v = Foo { a_b: 2 }; +        assert_eq!(encode!(v), map! { a_b, Integer(2) }); +        assert_eq!(v, decode!(Table(encode!(v)))); + +        let mut m = BTreeMap::new(); +        m.insert("a-b".to_string(), Integer(2)); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn nested() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: isize, b: Bar } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { a: String } + +        let v = Foo { a: 2, b: Bar { a: "test".to_string() } }; +        assert_eq!(encode!(v), +                   map! { +                       a, Integer(2), +                       b, Table(map! { +                           a, Value::String("test".to_string()) +                       }) +                   }); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn application_decode_error() { +        #[derive(PartialEq, Debug)] +        struct Range10(usize); +        impl Decodable for Range10 { +             fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Range10, D::Error> { +                 let x: usize = try!(Decodable::decode(d)); +                 if x > 10 { +                     Err(d.error("Value out of range!")) +                 } else { +                     Ok(Range10(x)) +                 } +             } +        } +        let mut d_good = Decoder::new(Integer(5)); +        let mut d_bad1 = Decoder::new(Value::String("not an isize".to_string())); +        let mut d_bad2 = Decoder::new(Integer(11)); + +        assert_eq!(Ok(Range10(5)), Decodable::decode(&mut d_good)); + +        let err1: Result<Range10, _> = Decodable::decode(&mut d_bad1); +        assert!(err1.is_err()); +        let err2: Result<Range10, _> = Decodable::decode(&mut d_bad2); +        assert!(err2.is_err()); +    } + +    #[test] +    fn array() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Vec<isize> } + +        let v = Foo { a: vec![1, 2, 3, 4] }; +        assert_eq!(encode!(v), +                   map! { +                       a, Array(vec![ +                            Integer(1), +                            Integer(2), +                            Integer(3), +                            Integer(4) +                       ]) +                   }); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn tuple() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: (isize, isize, isize, isize) } + +        let v = Foo { a: (1, 2, 3, 4) }; +        assert_eq!(encode!(v), +                   map! { +                       a, Array(vec![ +                            Integer(1), +                            Integer(2), +                            Integer(3), +                            Integer(4) +                       ]) +                   }); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn inner_structs_with_options() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { +            a: Option<Box<Foo>>, +            b: Bar, +        } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { +            a: String, +            b: f64, +        } + +        let v = Foo { +            a: Some(Box::new(Foo { +                a: None, +                b: Bar { a: "foo".to_string(), b: 4.5 }, +            })), +            b: Bar { a: "bar".to_string(), b: 1.0 }, +        }; +        assert_eq!(encode!(v), +                   map! { +                       a, Table(map! { +                           b, Table(map! { +                               a, Value::String("foo".to_string()), +                               b, Float(4.5) +                           }) +                       }), +                       b, Table(map! { +                           a, Value::String("bar".to_string()), +                           b, Float(1.0) +                       }) +                   }); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn hashmap() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { +            map: BTreeMap<String, isize>, +            set: HashSet<char>, +        } + +        let v = Foo { +            map: { +                let mut m = BTreeMap::new(); +                m.insert("foo".to_string(), 10); +                m.insert("bar".to_string(), 4); +                m +            }, +            set: { +                let mut s = HashSet::new(); +                s.insert('a'); +                s +            }, +        }; +        assert_eq!(encode!(v), +            map! { +                map, Table(map! { +                    foo, Integer(10), +                    bar, Integer(4) +                }), +                set, Array(vec![Value::String("a".to_string())]) +            } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn tuple_struct() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo(isize, String, f64); + +        let v = Foo(1, "foo".to_string(), 4.5); +        assert_eq!( +            encode!(v), +            map! { +                _field0, Integer(1), +                _field1, Value::String("foo".to_string()), +                _field2, Float(4.5) +            } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn table_array() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Vec<Bar>, } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { a: isize } + +        let v = Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] }; +        assert_eq!( +            encode!(v), +            map! { +                a, Array(vec![ +                    Table(map!{ a, Integer(1) }), +                    Table(map!{ a, Integer(2) }), +                ]) +            } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn type_errors() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { bar: isize } + +        let mut d = Decoder::new(Table(map! { +            bar, Float(1.0) +        })); +        let a: Result<Foo, DecodeError> = Decodable::decode(&mut d); +        match a { +            Ok(..) => panic!("should not have decoded"), +            Err(e) => { +                assert_eq!(format!("{}", e), +                           "expected a value of type `integer`, but \ +                            found a value of type `float` for the key `bar`"); +            } +        } +    } + +    #[test] +    fn missing_errors() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { bar: isize } + +        let mut d = Decoder::new(Table(map! { +        })); +        let a: Result<Foo, DecodeError> = Decodable::decode(&mut d); +        match a { +            Ok(..) => panic!("should not have decoded"), +            Err(e) => { +                assert_eq!(format!("{}", e), +                           "expected a value of type `integer` for the key `bar`"); +            } +        } +    } + +    #[test] +    fn parse_enum() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: E } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        enum E { +            Bar(isize), +            Baz(f64), +            Last(Foo2), +        } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo2 { +            test: String, +        } + +        let v = Foo { a: E::Bar(10) }; +        assert_eq!( +            encode!(v), +            map! { a, Integer(10) } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); + +        let v = Foo { a: E::Baz(10.2) }; +        assert_eq!( +            encode!(v), +            map! { a, Float(10.2) } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); + +        let v = Foo { a: E::Last(Foo2 { test: "test".to_string() }) }; +        assert_eq!( +            encode!(v), +            map! { a, Table(map! { test, Value::String("test".to_string()) }) } +        ); +        assert_eq!(v, decode!(Table(encode!(v)))); +    } + +    #[test] +    fn unused_fields() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: isize } + +        let v = Foo { a: 2 }; +        let mut d = Decoder::new(Table(map! { +            a, Integer(2), +            b, Integer(5) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, Some(Table(map! { +            b, Integer(5) +        }))); +    } + +    #[test] +    fn unused_fields2() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Bar } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { a: isize } + +        let v = Foo { a: Bar { a: 2 } }; +        let mut d = Decoder::new(Table(map! { +            a, Table(map! { +                a, Integer(2), +                b, Integer(5) +            }) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, Some(Table(map! { +            a, Table(map! { +                b, Integer(5) +            }) +        }))); +    } + +    #[test] +    fn unused_fields3() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Bar } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { a: isize } + +        let v = Foo { a: Bar { a: 2 } }; +        let mut d = Decoder::new(Table(map! { +            a, Table(map! { +                a, Integer(2) +            }) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, None); +    } + +    #[test] +    fn unused_fields4() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: BTreeMap<String, String> } + +        let v = Foo { a: map! { a, "foo".to_string() } }; +        let mut d = Decoder::new(Table(map! { +            a, Table(map! { +                a, Value::String("foo".to_string()) +            }) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, None); +    } + +    #[test] +    fn unused_fields5() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Vec<String> } + +        let v = Foo { a: vec!["a".to_string()] }; +        let mut d = Decoder::new(Table(map! { +            a, Array(vec![Value::String("a".to_string())]) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, None); +    } + +    #[test] +    fn unused_fields6() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Option<Vec<String>> } + +        let v = Foo { a: Some(vec![]) }; +        let mut d = Decoder::new(Table(map! { +            a, Array(vec![]) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, None); +    } + +    #[test] +    fn unused_fields7() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Vec<Bar> } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar { a: isize } + +        let v = Foo { a: vec![Bar { a: 1 }] }; +        let mut d = Decoder::new(Table(map! { +            a, Array(vec![Table(map! { +                a, Integer(1), +                b, Integer(2) +            })]) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        assert_eq!(d.toml, Some(Table(map! { +            a, Array(vec![Table(map! { +                b, Integer(2) +            })]) +        }))); +    } + +    #[test] +    fn empty_arrays() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Vec<Bar> } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar; + +        let v = Foo { a: vec![] }; +        let mut d = Decoder::new(Table(map! {})); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); +    } + +    #[test] +    fn empty_arrays2() { +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Foo { a: Option<Vec<Bar>> } +        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] +        struct Bar; + +        let v = Foo { a: None }; +        let mut d = Decoder::new(Table(map! {})); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); + +        let v = Foo { a: Some(vec![]) }; +        let mut d = Decoder::new(Table(map! { +            a, Array(vec![]) +        })); +        assert_eq!(v, Decodable::decode(&mut d).unwrap()); +    } + +    #[test] +    fn round_trip() { +        let toml = r#" +              [test] +              foo = "bar" + +              [[values]] +              foo = "baz" + +              [[values]] +              foo = "qux" +        "#; + +        let value: Value = toml.parse().unwrap(); +        let val2 = ::encode_str(&value).parse().unwrap(); +        assert_eq!(value, val2); +    } +} @@ -39,26 +39,25 @@  #![deny(missing_docs)]  #![cfg_attr(test, deny(warnings))] -extern crate rustc_serialize; +#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;  use std::collections::BTreeMap;  use std::str::FromStr;  use std::string;  pub use parser::{Parser, ParserError}; -pub use serialization::{Encoder, encode, encode_str}; -pub use serialization::{Decoder, decode, decode_str}; -pub use serialization::Error; -pub use serialization::Error::{NeedsKey, NoValue}; -pub use serialization::Error::{InvalidMapKeyLocation, InvalidMapKeyType}; -pub use serialization::{DecodeError, DecodeErrorKind}; -pub use serialization::DecodeErrorKind::{ApplicationError, ExpectedField}; -pub use serialization::DecodeErrorKind::{ExpectedMapElement, ExpectedMapKey, NoEnumVariants}; -pub use serialization::DecodeErrorKind::{ExpectedType, NilTooLong}; + +#[cfg(any(feature = "rustc-serialize", feature = "serde"))] +pub use self::encoder::{Encoder, Error, encode, encode_str}; +#[cfg(any(feature = "rustc-serialize", feature = "serde"))] +pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};  mod parser;  mod display; -mod serialization; +#[cfg(any(feature = "rustc-serialize", feature = "serde"))] +mod encoder; +#[cfg(any(feature = "rustc-serialize", feature = "serde"))] +mod decoder;  /// Representation of a TOML value.  #[derive(PartialEq, Clone, Debug)] @@ -203,37 +202,6 @@ impl Value {      }  } -impl rustc_serialize::Encodable for Value { -    fn encode<E>(&self, e: &mut E) -> Result<(), E::Error> -        where E: rustc_serialize::Encoder -    { -        match *self { -            Value::String(ref s) => e.emit_str(s), -            Value::Integer(i) => e.emit_i64(i), -            Value::Float(f) => e.emit_f64(f), -            Value::Boolean(b) => e.emit_bool(b), -            Value::Datetime(ref s) => e.emit_str(s), -            Value::Array(ref a) => { -                e.emit_seq(a.len(), |e| { -                    for item in a { -                        try!(item.encode(e)); -                    } -                    Ok(()) -                }) -            } -            Value::Table(ref t) => { -                e.emit_map(t.len(), |e| { -                    for (i, (key, value)) in t.iter().enumerate() { -                        try!(e.emit_map_elt_key(i, |e| e.emit_str(key))); -                        try!(e.emit_map_elt_val(i, |e| value.encode(e))); -                    } -                    Ok(()) -                }) -            } -        } -    } -} -  impl FromStr for Value {      type Err = Vec<ParserError>;      fn from_str(s: &str) -> Result<Value, Vec<ParserError>> { @@ -292,22 +260,4 @@ mod tests {          let foo = value.lookup("values.str.foo");          assert!(foo.is_none());      } - -    #[test] -    fn round_trip() { -        let toml = r#" -              [test] -              foo = "bar" - -              [[values]] -              foo = "baz" - -              [[values]] -              foo = "qux" -        "#; - -        let value: Value = toml.parse().unwrap(); -        let val2 = ::encode_str(&value).parse().unwrap(); -        assert_eq!(value, val2); -    }  } diff --git a/src/serialization.rs b/src/serialization.rs deleted file mode 100644 index 565b4e7..0000000 --- a/src/serialization.rs +++ /dev/null @@ -1,1279 +0,0 @@ -use std::collections::BTreeMap; -use std::mem; -use std::fmt; -use std::error::Error as StdError; - -use rustc_serialize; -use {Value, Parser}; -use Table as TomlTable; -use Value::{Table, Array, Integer, Float, Boolean}; - -use self::EncoderState::{Start, NextKey, NextArray, NextMapKey}; -use self::Error::{NeedsKey, NoValue, InvalidMapKeyLocation, InvalidMapKeyType}; -use self::DecodeErrorKind::{ApplicationError, ExpectedField, ExpectedType, ExpectedMapKey}; -use self::DecodeErrorKind::{ExpectedMapElement, NoEnumVariants, NilTooLong}; - -/// A structure to transform Rust values into TOML values. -/// -/// This encoder implements the serialization `Encoder` interface, allowing -/// `Encodable` rust types to be fed into the encoder. The output of this -/// encoder is a TOML `Table` structure. The resulting TOML can be stringified -/// if necessary. -/// -/// # Example -/// -/// ``` -/// extern crate rustc_serialize; -/// extern crate toml; -/// -/// # fn main() { -/// use toml::{Encoder, Value}; -/// use rustc_serialize::Encodable; -/// -/// #[derive(RustcEncodable)] -/// struct MyStruct { foo: isize, bar: String } -/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() }; -/// -/// let mut e = Encoder::new(); -/// my_struct.encode(&mut e).unwrap(); -/// -/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4))) -/// # } -/// ``` -pub struct Encoder { -    /// Output TOML that is emitted. The current version of this encoder forces -    /// the top-level representation of a structure to be a table. -    /// -    /// This field can be used to extract the return value after feeding a value -    /// into this `Encoder`. -    pub toml: TomlTable, -    state: EncoderState, -} - -/// A structure to transform TOML values into Rust values. -/// -/// This decoder implements the serialization `Decoder` interface, allowing -/// `Decodable` types to be generated by this decoder. The input is any -/// arbitrary TOML value. -pub struct Decoder { -    /// The TOML value left over after decoding. This can be used to inspect -    /// whether fields were decoded or not. -    pub toml: Option<Value>, -    cur_field: Option<String>, -} - -/// Enumeration of errors which can occur while encoding a rust value into a -/// TOML value. -#[allow(missing_copy_implementations)] -#[derive(Debug)] -pub enum Error { -    /// Indication that a key was needed when a value was emitted, but no key -    /// was previously emitted. -    NeedsKey, -    /// Indication that a key was emitted, but not value was emitted. -    NoValue, -    /// Indicates that a map key was attempted to be emitted at an invalid -    /// location. -    InvalidMapKeyLocation, -    /// Indicates that a type other than a string was attempted to be used as a -    /// map key type. -    InvalidMapKeyType, -} - -/// Description for errors which can occur while decoding a type. -#[derive(PartialEq, Debug)] -pub struct DecodeError { -    /// Field that this error applies to. -    pub field: Option<String>, -    /// The type of error which occurred while decoding, -    pub kind: DecodeErrorKind, -} - -/// Enumeration of possible errors which can occur while decoding a structure. -#[derive(PartialEq, Debug)] -pub enum DecodeErrorKind { -    /// An error flagged by the application, e.g. value out of range -    ApplicationError(String), -    /// A field was expected, but none was found. -    ExpectedField(/* type */ &'static str), -    /// A field was found, but it had the wrong type. -    ExpectedType(/* expected */ &'static str, /* found */ &'static str), -    /// The nth map key was expected, but none was found. -    ExpectedMapKey(usize), -    /// The nth map element was expected, but none was found. -    ExpectedMapElement(usize), -    /// An enum decoding was requested, but no variants were supplied -    NoEnumVariants, -    /// The unit type was being decoded, but a non-zero length string was found -    NilTooLong -} - -#[derive(PartialEq)] -enum EncoderState { -    Start, -    NextKey(String), -    NextArray(Vec<Value>), -    NextMapKey, -} - -/// Encodes an encodable value into a TOML value. -/// -/// This function expects the type given to represent a TOML table in some form. -/// If encoding encounters an error, then this function will fail the task. -pub fn encode<T: rustc_serialize::Encodable>(t: &T) -> Value { -    let mut e = Encoder::new(); -    t.encode(&mut e).unwrap(); -    Table(e.toml) -} - -/// Encodes an encodable value into a TOML string. -/// -/// This function expects the type given to represent a TOML table in some form. -/// If encoding encounters an error, then this function will fail the task. -pub fn encode_str<T: rustc_serialize::Encodable>(t: &T) -> String { -    format!("{}", encode(t)) -} - -impl Encoder { -    /// Constructs a new encoder which will emit to the given output stream. -    pub fn new() -> Encoder { -        Encoder { state: Start, toml: BTreeMap::new() } -    } - -    fn emit_value(&mut self, v: Value) -> Result<(), Error> { -        match mem::replace(&mut self.state, Start) { -            NextKey(key) => { self.toml.insert(key, v); Ok(()) } -            NextArray(mut vec) => { -                // TODO: validate types -                vec.push(v); -                self.state = NextArray(vec); -                Ok(()) -            } -            NextMapKey => { -                match v { -                    Value::String(s) => { self.state = NextKey(s); Ok(()) } -                    _ => Err(InvalidMapKeyType) -                } -            } -            _ => Err(NeedsKey) -        } -    } -} - -impl rustc_serialize::Encoder for Encoder { -    type Error = Error; - -    fn emit_nil(&mut self) -> Result<(), Error> { Ok(()) } -    fn emit_usize(&mut self, v: usize) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_u8(&mut self, v: u8) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_u16(&mut self, v: u16) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_u32(&mut self, v: u32) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_u64(&mut self, v: u64) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_isize(&mut self, v: isize) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_i8(&mut self, v: i8) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_i16(&mut self, v: i16) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_i32(&mut self, v: i32) -> Result<(), Error> { -        self.emit_i64(v as i64) -    } -    fn emit_i64(&mut self, v: i64) -> Result<(), Error> { -        self.emit_value(Integer(v)) -    } -    fn emit_bool(&mut self, v: bool) -> Result<(), Error> { -        self.emit_value(Boolean(v)) -    } -    fn emit_f32(&mut self, v: f32) -> Result<(), Error> { self.emit_f64(v as f64) } -    fn emit_f64(&mut self, v: f64) -> Result<(), Error> { -        self.emit_value(Float(v)) -    } -    fn emit_char(&mut self, v: char) -> Result<(), Error> { -        self.emit_str(&*format!("{}", v)) -    } -    fn emit_str(&mut self, v: &str) -> Result<(), Error> { -        self.emit_value(Value::String(format!("{}", v))) -    } -    fn emit_enum<F>(&mut self, _name: &str, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_enum_variant<F>(&mut self, _v_name: &str, _v_id: usize, -                            _len: usize, f: F) -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_enum_struct_variant<F>(&mut self, _v_name: &str, _v_id: usize, -                                   _len: usize, -                                   _f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        panic!() -    } -    fn emit_enum_struct_variant_field<F>(&mut self, -                                         _f_name: &str, -                                         _f_idx: usize, -                                         _f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        panic!() -    } -    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        match mem::replace(&mut self.state, Start) { -            NextKey(key) => { -                let mut nested = Encoder::new(); -                try!(f(&mut nested)); -                self.toml.insert(key, Table(nested.toml)); -                Ok(()) -            } -            NextArray(mut arr) => { -                let mut nested = Encoder::new(); -                try!(f(&mut nested)); -                arr.push(Table(nested.toml)); -                self.state = NextArray(arr); -                Ok(()) -            } -            Start => f(self), -            NextMapKey => Err(InvalidMapKeyLocation), -        } -    } -    fn emit_struct_field<F>(&mut self, f_name: &str, _f_idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        let old = mem::replace(&mut self.state, -                               NextKey(format!("{}", f_name))); -        try!(f(self)); -        if self.state != Start { -            return Err(NoValue) -        } -        self.state = old; -        Ok(()) -    } -    fn emit_tuple<F>(&mut self, len: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        self.emit_seq(len, f) -    } -    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        self.emit_seq_elt(idx, f) -    } -    fn emit_tuple_struct<F>(&mut self, _name: &str, _len: usize, _f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        unimplemented!() -    } -    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: usize, _f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        unimplemented!() -    } -    fn emit_option<F>(&mut self, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_option_none(&mut self) -> Result<(), Error> { -        match mem::replace(&mut self.state, Start) { -            Start => unreachable!(), -            NextKey(_) => Ok(()), -            NextArray(..) => panic!("how to encode None in an array?"), -            NextMapKey => Err(InvalidMapKeyLocation), -        } -    } -    fn emit_option_some<F>(&mut self, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_seq<F>(&mut self, _len: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        let old = mem::replace(&mut self.state, NextArray(Vec::new())); -        try!(f(self)); -        match mem::replace(&mut self.state, old) { -            NextArray(v) => self.emit_value(Array(v)), -            _ => unreachable!(), -        } -    } -    fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -    fn emit_map<F>(&mut self, len: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        self.emit_struct("foo", len, f) -    } -    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        match mem::replace(&mut self.state, NextMapKey) { -            Start => {} -            _ => return Err(InvalidMapKeyLocation), -        } -        try!(f(self)); -        match self.state { -            NextKey(_) => Ok(()), -            _ => Err(InvalidMapKeyLocation), -        } -    } -    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -        -> Result<(), Error> -        where F: FnOnce(&mut Encoder) -> Result<(), Error> -    { -        f(self) -    } -} - -/// Decodes a TOML value into a decodable type. -/// -/// This function will consume the given TOML value and attempt to decode it -/// into the type specified. If decoding fails, `None` will be returned. If a -/// finer-grained error is desired, then it is recommended to use `Decodable` -/// directly. -pub fn decode<T: rustc_serialize::Decodable>(toml: Value) -    -> Option<T> -{ -    rustc_serialize::Decodable::decode(&mut Decoder::new(toml)).ok() -} - -/// Decodes a string into a toml-encoded value. -/// -/// This function will parse the given string into a TOML value, and then parse -/// the TOML value into the desired type. If any error occurs `None` is return. -/// If more fine-grained errors are desired, these steps should be driven -/// manually. -pub fn decode_str<T: rustc_serialize::Decodable>(s: &str) -    -> Option<T> -{ -    Parser::new(s).parse().and_then(|t| decode(Table(t))) -} - -impl Decoder { -    /// Creates a new decoder, consuming the TOML value to decode. -    /// -    /// This decoder can be passed to the `Decodable` methods or driven -    /// manually. -    pub fn new(toml: Value) -> Decoder { -        Decoder { toml: Some(toml), cur_field: None } -    } - -    fn sub_decoder(&self, toml: Option<Value>, field: &str) -> Decoder { -        Decoder { -            toml: toml, -            cur_field: if field.len() == 0 { -                self.cur_field.clone() -            } else { -                match self.cur_field { -                    None => Some(format!("{}", field)), -                    Some(ref s) => Some(format!("{}.{}", s, field)) -                } -            } -        } -    } - -    fn err(&self, kind: DecodeErrorKind) -> DecodeError { -        DecodeError { -            field: self.cur_field.clone(), -            kind: kind, -        } -    } - -    fn mismatch(&self, expected: &'static str, -                found: &Option<Value>) -> DecodeError{ -        match *found { -            Some(ref val) => self.err(ExpectedType(expected, val.type_str())), -            None => self.err(ExpectedField(expected)), -        } -    } -} - -impl rustc_serialize::Decoder for Decoder { -    type Error = DecodeError; -    fn read_nil(&mut self) -> Result<(), DecodeError> { -        match self.toml { -            Some(Value::String(ref s)) if s.len() == 0 => {} -            Some(Value::String(..)) => return Err(self.err(NilTooLong)), -            ref found => return Err(self.mismatch("string", found)), -        } -        self.toml.take(); -        Ok(()) -    } -    fn read_usize(&mut self) -> Result<usize, DecodeError> { -        self.read_i64().map(|i| i as usize) -    } -    fn read_u64(&mut self) -> Result<u64, DecodeError> { -        self.read_i64().map(|i| i as u64) -    } -    fn read_u32(&mut self) -> Result<u32, DecodeError> { -        self.read_i64().map(|i| i as u32) -    } -    fn read_u16(&mut self) -> Result<u16, DecodeError> { -        self.read_i64().map(|i| i as u16) -    } -    fn read_u8(&mut self) -> Result<u8, DecodeError> { -        self.read_i64().map(|i| i as u8) -    } -    fn read_isize(&mut self) -> Result<isize, DecodeError> { -        self.read_i64().map(|i| i as isize) -    } -    fn read_i64(&mut self) -> Result<i64, DecodeError> { -        match self.toml { -            Some(Integer(i)) => { self.toml.take(); Ok(i) } -            ref found => Err(self.mismatch("integer", found)), -        } -    } -    fn read_i32(&mut self) -> Result<i32, DecodeError> { -        self.read_i64().map(|i| i as i32) -    } -    fn read_i16(&mut self) -> Result<i16, DecodeError> { -        self.read_i64().map(|i| i as i16) -    } -    fn read_i8(&mut self) -> Result<i8, DecodeError> { -        self.read_i64().map(|i| i as i8) -    } -    fn read_bool(&mut self) -> Result<bool, DecodeError> { -        match self.toml { -            Some(Boolean(b)) => { self.toml.take(); Ok(b) } -            ref found => Err(self.mismatch("bool", found)), -        } -    } -    fn read_f64(&mut self) -> Result<f64, DecodeError> { -        match self.toml { -            Some(Float(f)) => Ok(f), -            ref found => Err(self.mismatch("float", found)), -        } -    } -    fn read_f32(&mut self) -> Result<f32, DecodeError> { -        self.read_f64().map(|f| f as f32) -    } -    fn read_char(&mut self) -> Result<char, DecodeError> { -        let ch = match self.toml { -            Some(Value::String(ref s)) if s.chars().count() == 1 => -                s.chars().next().unwrap(), -            ref found => return Err(self.mismatch("string", found)), -        }; -        self.toml.take(); -        Ok(ch) -    } -    fn read_str(&mut self) -> Result<String, DecodeError> { -        match self.toml.take() { -            Some(Value::String(s)) => Ok(s), -            found => { -                let err = Err(self.mismatch("string", &found)); -                self.toml = found; -                err -            } -        } -    } - -    // Compound types: -    fn read_enum<T, F>(&mut self, _name: &str, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        f(self) -    } - -    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -        -> Result<T, DecodeError> -        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError> -    { -        let mut first_error = None; -        for i in 0..names.len() { -            let mut d = self.sub_decoder(self.toml.clone(), ""); -            match f(&mut d, i) { -                Ok(t) => { self.toml = d.toml; return Ok(t) } -                Err(e) => { -                    if first_error.is_none() { -                        first_error = Some(e); -                    } -                } -            } -        } -        Err(first_error.unwrap_or_else(|| self.err(NoEnumVariants))) -    } -    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        f(self) -    } - -    fn read_enum_struct_variant<T, F>(&mut self, _names: &[&str], _f: F) -        -> Result<T, DecodeError> -        where F: FnMut(&mut Decoder, usize) -> Result<T, DecodeError> -    { -        panic!() -    } -    fn read_enum_struct_variant_field<T, F>(&mut self, -                                            _f_name: &str, -                                            _f_idx: usize, -                                            _f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        panic!() -    } - -    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        match self.toml { -            Some(Table(..)) => { -                let ret = try!(f(self)); -                match self.toml { -                    Some(Table(ref t)) if t.len() == 0 => {} -                    _ => return Ok(ret) -                } -                self.toml.take(); -                Ok(ret) -            } -            ref found => Err(self.mismatch("table", found)), -        } -    } -    fn read_struct_field<T, F>(&mut self, f_name: &str, _f_idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        let field = format!("{}", f_name); -        let toml = match self.toml { -            Some(Table(ref mut table)) => { -                table.remove(&field) -                    .or_else(|| table.remove(&f_name.replace("_", "-"))) -            }, -            ref found => return Err(self.mismatch("table", found)), -        }; -        let mut d = self.sub_decoder(toml, f_name); -        let ret = try!(f(&mut d)); -        match d.toml { -            Some(value) => match self.toml { -                Some(Table(ref mut table)) => { table.insert(field, value); } -                _ => {} -            }, -            None => {} -        } -        Ok(ret) -    } - -    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        self.read_seq(move |d, len| { -            assert!(len == tuple_len, -                    "expected tuple of length `{}`, found tuple \ -                         of length `{}`", tuple_len, len); -            f(d) -        }) -    } -    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        self.read_seq_elt(a_idx, f) -    } - -    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, _len: usize, _f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        panic!() -    } -    fn read_tuple_struct_arg<T, F>(&mut self, _a_idx: usize, _f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        panic!() -    } - -    // Specialized types: -    fn read_option<T, F>(&mut self, mut f: F) -        -> Result<T, DecodeError> -        where F: FnMut(&mut Decoder, bool) -> Result<T, DecodeError> -    { -        match self.toml { -            Some(..) => f(self, true), -            None => f(self, false), -        } -    } - -    fn read_seq<T, F>(&mut self, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError> -    { -        let len = match self.toml { -            Some(Array(ref arr)) => arr.len(), -            None => 0, -            ref found => return Err(self.mismatch("array", found)), -        }; -        let ret = try!(f(self, len)); -        match self.toml { -            Some(Array(ref mut arr)) => { -                arr.retain(|slot| slot.as_integer() != Some(0)); -                if arr.len() != 0 { return Ok(ret) } -            } -            _ => return Ok(ret) -        } -        self.toml.take(); -        Ok(ret) -    } -    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        let toml = match self.toml { -            Some(Array(ref mut arr)) => mem::replace(&mut arr[idx], Integer(0)), -            ref found => return Err(self.mismatch("array", found)), -        }; -        let mut d = self.sub_decoder(Some(toml), ""); -        let ret = try!(f(&mut d)); -        match d.toml { -            Some(toml) => match self.toml { -                Some(Array(ref mut arr)) => arr[idx] = toml, -                _ => {} -            }, -            _ => {} -        } -        Ok(ret) -    } - -    fn read_map<T, F>(&mut self, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError> -    { -        let len = match self.toml { -            Some(Table(ref table)) => table.len(), -            ref found => return Err(self.mismatch("table", found)), -        }; -        let ret = try!(f(self, len)); -        self.toml.take(); -        Ok(ret) -    } -    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        match self.toml { -            Some(Table(ref table)) => { -                match table.iter().skip(idx).next() { -                    Some((key, _)) => { -                        let val = Value::String(format!("{}", key)); -                        f(&mut self.sub_decoder(Some(val), &**key)) -                    } -                    None => Err(self.err(ExpectedMapKey(idx))), -                } -            } -            ref found => Err(self.mismatch("table", found)), -        } -    } -    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -        -> Result<T, DecodeError> -        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError> -    { -        match self.toml { -            Some(Table(ref table)) => { -                match table.iter().skip(idx).next() { -                    Some((_, value)) => { -                        // XXX: this shouldn't clone -                        f(&mut self.sub_decoder(Some(value.clone()), "")) -                    } -                    None => Err(self.err(ExpectedMapElement(idx))), -                } -            } -            ref found => Err(self.mismatch("table", found)), -        } -    } - -    fn error(&mut self, err: &str) -> DecodeError { -        DecodeError { -            field: self.cur_field.clone(), -            kind: ApplicationError(format!("{}", err)) -        } -    } -} - -impl fmt::Display for DecodeError { -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -        try!(match self.kind { -            ApplicationError(ref err) => { -                write!(f, "{}", err) -            } -            ExpectedField(expected_type) => { -                if expected_type == "table" { -                    write!(f, "expected a section") -                } else { -                    write!(f, "expected a value of type `{}`", expected_type) -                } -            } -            ExpectedType(expected, found) => { -                fn humanize(s: &str) -> String { -                    if s == "section" { -                        format!("a section") -                    } else { -                        format!("a value of type `{}`", s) -                    } -                } -                write!(f, "expected {}, but found {}", -                       humanize(expected), -                       humanize(found)) -            } -            ExpectedMapKey(idx) => { -                write!(f, "expected at least {} keys", idx + 1) -            } -            ExpectedMapElement(idx) => { -                write!(f, "expected at least {} elements", idx + 1) -            } -            NoEnumVariants => { -                write!(f, "expected an enum variant to decode to") -            } -            NilTooLong => { -                write!(f, "expected 0-length string") -            } -        }); -        match self.field { -            Some(ref s) => { -                write!(f, " for the key `{}`", s) -            } -            None => Ok(()) -        } -    } -} - -impl StdError for DecodeError { -    fn description(&self) -> &str { -        match self.kind { -            ApplicationError(ref s) => &**s, -            ExpectedField(..) => "expected a field", -            ExpectedType(..) => "expected a type", -            ExpectedMapKey(..) => "expected a map key", -            ExpectedMapElement(..) => "expected a map element", -            NoEnumVariants => "no enum variants to decode to", -            NilTooLong => "nonzero length string representing nil", -        } -    } -} - -impl fmt::Display for Error { -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -        match *self { -            NeedsKey => write!(f, "need a key to encode"), -            NoValue => write!(f, "not value to emit for a previous key"), -            InvalidMapKeyLocation => write!(f, "a map cannot be emitted at \ -                                                this location"), -            InvalidMapKeyType => write!(f, "only strings can be used as \ -                                            key types"), -        } -    } -} - -impl StdError for Error { -    fn description(&self) -> &str { "TOML encoding error" } -} - -#[cfg(test)] -mod tests { -    use std::collections::{BTreeMap, HashSet}; -    use rustc_serialize::{self, Encodable, Decodable}; - -    use super::{Encoder, Decoder, DecodeError}; -    use Value; -    use Value::{Table, Integer, Array, Float}; - -    macro_rules! encode( ($t:expr) => ({ -        let mut e = Encoder::new(); -        $t.encode(&mut e).unwrap(); -        e.toml -    }) ); - -    macro_rules! decode( ($t:expr) => ({ -        let mut d = Decoder::new($t); -        Decodable::decode(&mut d).unwrap() -    }) ); - -    macro_rules! map( ($($k:ident, $v:expr),*) => ({ -        let mut _m = BTreeMap::new(); -        $(_m.insert(stringify!($k).to_string(), $v);)* -        _m -    }) ); - -    #[test] -    fn smoke() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: isize } - -        let v = Foo { a: 2 }; -        assert_eq!(encode!(v), map! { a, Integer(2) }); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn smoke_hyphen() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a_b: isize } - -        let v = Foo { a_b: 2 }; -        assert_eq!(encode!(v), map! { a_b, Integer(2) }); -        assert_eq!(v, decode!(Table(encode!(v)))); - -        let mut m = BTreeMap::new(); -        m.insert("a-b".to_string(), Integer(2)); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn nested() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: isize, b: Bar } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { a: String } - -        let v = Foo { a: 2, b: Bar { a: "test".to_string() } }; -        assert_eq!(encode!(v), -                   map! { -                       a, Integer(2), -                       b, Table(map! { -                           a, Value::String("test".to_string()) -                       }) -                   }); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn application_decode_error() { -        #[derive(PartialEq, Debug)] -        struct Range10(usize); -        impl Decodable for Range10 { -             fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Range10, D::Error> { -                 let x: usize = try!(Decodable::decode(d)); -                 if x > 10 { -                     Err(d.error("Value out of range!")) -                 } else { -                     Ok(Range10(x)) -                 } -             } -        } -        let mut d_good = Decoder::new(Integer(5)); -        let mut d_bad1 = Decoder::new(Value::String("not an isize".to_string())); -        let mut d_bad2 = Decoder::new(Integer(11)); - -        assert_eq!(Ok(Range10(5)), Decodable::decode(&mut d_good)); - -        let err1: Result<Range10, _> = Decodable::decode(&mut d_bad1); -        assert!(err1.is_err()); -        let err2: Result<Range10, _> = Decodable::decode(&mut d_bad2); -        assert!(err2.is_err()); -    } - -    #[test] -    fn array() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Vec<isize> } - -        let v = Foo { a: vec![1, 2, 3, 4] }; -        assert_eq!(encode!(v), -                   map! { -                       a, Array(vec![ -                            Integer(1), -                            Integer(2), -                            Integer(3), -                            Integer(4) -                       ]) -                   }); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn tuple() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: (isize, isize, isize, isize) } - -        let v = Foo { a: (1, 2, 3, 4) }; -        assert_eq!(encode!(v), -                   map! { -                       a, Array(vec![ -                            Integer(1), -                            Integer(2), -                            Integer(3), -                            Integer(4) -                       ]) -                   }); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn inner_structs_with_options() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { -            a: Option<Box<Foo>>, -            b: Bar, -        } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { -            a: String, -            b: f64, -        } - -        let v = Foo { -            a: Some(Box::new(Foo { -                a: None, -                b: Bar { a: "foo".to_string(), b: 4.5 }, -            })), -            b: Bar { a: "bar".to_string(), b: 1.0 }, -        }; -        assert_eq!(encode!(v), -                   map! { -                       a, Table(map! { -                           b, Table(map! { -                               a, Value::String("foo".to_string()), -                               b, Float(4.5) -                           }) -                       }), -                       b, Table(map! { -                           a, Value::String("bar".to_string()), -                           b, Float(1.0) -                       }) -                   }); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn hashmap() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { -            map: BTreeMap<String, isize>, -            set: HashSet<char>, -        } - -        let v = Foo { -            map: { -                let mut m = BTreeMap::new(); -                m.insert("foo".to_string(), 10); -                m.insert("bar".to_string(), 4); -                m -            }, -            set: { -                let mut s = HashSet::new(); -                s.insert('a'); -                s -            }, -        }; -        assert_eq!(encode!(v), -            map! { -                map, Table(map! { -                    foo, Integer(10), -                    bar, Integer(4) -                }), -                set, Array(vec![Value::String("a".to_string())]) -            } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn tuple_struct() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo(isize, String, f64); - -        let v = Foo(1, "foo".to_string(), 4.5); -        assert_eq!( -            encode!(v), -            map! { -                _field0, Integer(1), -                _field1, Value::String("foo".to_string()), -                _field2, Float(4.5) -            } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn table_array() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Vec<Bar>, } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { a: isize } - -        let v = Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] }; -        assert_eq!( -            encode!(v), -            map! { -                a, Array(vec![ -                    Table(map!{ a, Integer(1) }), -                    Table(map!{ a, Integer(2) }), -                ]) -            } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn type_errors() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { bar: isize } - -        let mut d = Decoder::new(Table(map! { -            bar, Float(1.0) -        })); -        let a: Result<Foo, DecodeError> = Decodable::decode(&mut d); -        match a { -            Ok(..) => panic!("should not have decoded"), -            Err(e) => { -                assert_eq!(format!("{}", e), -                           "expected a value of type `integer`, but \ -                            found a value of type `float` for the key `bar`"); -            } -        } -    } - -    #[test] -    fn missing_errors() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { bar: isize } - -        let mut d = Decoder::new(Table(map! { -        })); -        let a: Result<Foo, DecodeError> = Decodable::decode(&mut d); -        match a { -            Ok(..) => panic!("should not have decoded"), -            Err(e) => { -                assert_eq!(format!("{}", e), -                           "expected a value of type `integer` for the key `bar`"); -            } -        } -    } - -    #[test] -    fn parse_enum() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: E } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        enum E { -            Bar(isize), -            Baz(f64), -            Last(Foo2), -        } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo2 { -            test: String, -        } - -        let v = Foo { a: E::Bar(10) }; -        assert_eq!( -            encode!(v), -            map! { a, Integer(10) } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); - -        let v = Foo { a: E::Baz(10.2) }; -        assert_eq!( -            encode!(v), -            map! { a, Float(10.2) } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); - -        let v = Foo { a: E::Last(Foo2 { test: "test".to_string() }) }; -        assert_eq!( -            encode!(v), -            map! { a, Table(map! { test, Value::String("test".to_string()) }) } -        ); -        assert_eq!(v, decode!(Table(encode!(v)))); -    } - -    #[test] -    fn unused_fields() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: isize } - -        let v = Foo { a: 2 }; -        let mut d = Decoder::new(Table(map! { -            a, Integer(2), -            b, Integer(5) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, Some(Table(map! { -            b, Integer(5) -        }))); -    } - -    #[test] -    fn unused_fields2() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Bar } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { a: isize } - -        let v = Foo { a: Bar { a: 2 } }; -        let mut d = Decoder::new(Table(map! { -            a, Table(map! { -                a, Integer(2), -                b, Integer(5) -            }) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, Some(Table(map! { -            a, Table(map! { -                b, Integer(5) -            }) -        }))); -    } - -    #[test] -    fn unused_fields3() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Bar } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { a: isize } - -        let v = Foo { a: Bar { a: 2 } }; -        let mut d = Decoder::new(Table(map! { -            a, Table(map! { -                a, Integer(2) -            }) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, None); -    } - -    #[test] -    fn unused_fields4() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: BTreeMap<String, String> } - -        let v = Foo { a: map! { a, "foo".to_string() } }; -        let mut d = Decoder::new(Table(map! { -            a, Table(map! { -                a, Value::String("foo".to_string()) -            }) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, None); -    } - -    #[test] -    fn unused_fields5() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Vec<String> } - -        let v = Foo { a: vec!["a".to_string()] }; -        let mut d = Decoder::new(Table(map! { -            a, Array(vec![Value::String("a".to_string())]) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, None); -    } - -    #[test] -    fn unused_fields6() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Option<Vec<String>> } - -        let v = Foo { a: Some(vec![]) }; -        let mut d = Decoder::new(Table(map! { -            a, Array(vec![]) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, None); -    } - -    #[test] -    fn unused_fields7() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Vec<Bar> } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar { a: isize } - -        let v = Foo { a: vec![Bar { a: 1 }] }; -        let mut d = Decoder::new(Table(map! { -            a, Array(vec![Table(map! { -                a, Integer(1), -                b, Integer(2) -            })]) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        assert_eq!(d.toml, Some(Table(map! { -            a, Array(vec![Table(map! { -                b, Integer(2) -            })]) -        }))); -    } - -    #[test] -    fn empty_arrays() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Vec<Bar> } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar; - -        let v = Foo { a: vec![] }; -        let mut d = Decoder::new(Table(map! {})); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); -    } - -    #[test] -    fn empty_arrays2() { -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Foo { a: Option<Vec<Bar>> } -        #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] -        struct Bar; - -        let v = Foo { a: None }; -        let mut d = Decoder::new(Table(map! {})); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); - -        let v = Foo { a: Some(vec![]) }; -        let mut d = Decoder::new(Table(map! { -            a, Array(vec![]) -        })); -        assert_eq!(v, Decodable::decode(&mut d).unwrap()); -    } -}  |