From 2d49247b92f74cf760202b7d1a08d61804f45bca Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 2 Apr 2015 17:04:17 -0700 Subject: Modularize rustc-serialize support * Add rustc-serialize as a default feature * Make room for for serde support --- src/serialization.rs | 1279 -------------------------------------------------- 1 file changed, 1279 deletions(-) delete mode 100644 src/serialization.rs (limited to 'src/serialization.rs') 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, - cur_field: Option, -} - -/// 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, - /// 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), - 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: &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: &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(&mut self, _name: &str, f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - f(self) - } - fn emit_enum_variant(&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(&mut self, _a_idx: usize, f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - f(self) - } - fn emit_enum_struct_variant(&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(&mut self, - _f_name: &str, - _f_idx: usize, - _f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - panic!() - } - fn emit_struct(&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(&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(&mut self, len: usize, f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&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(&mut self, _name: &str, _len: usize, _f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - unimplemented!() - } - fn emit_tuple_struct_arg(&mut self, _f_idx: usize, _f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - unimplemented!() - } - fn emit_option(&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(&mut self, f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - f(self) - } - fn emit_seq(&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(&mut self, _idx: usize, f: F) - -> Result<(), Error> - where F: FnOnce(&mut Encoder) -> Result<(), Error> - { - f(self) - } - fn emit_map(&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(&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(&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(toml: Value) - -> Option -{ - 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(s: &str) - -> Option -{ - 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, 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) -> 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 { - self.read_i64().map(|i| i as usize) - } - fn read_u64(&mut self) -> Result { - self.read_i64().map(|i| i as u64) - } - fn read_u32(&mut self) -> Result { - self.read_i64().map(|i| i as u32) - } - fn read_u16(&mut self) -> Result { - self.read_i64().map(|i| i as u16) - } - fn read_u8(&mut self) -> Result { - self.read_i64().map(|i| i as u8) - } - fn read_isize(&mut self) -> Result { - self.read_i64().map(|i| i as isize) - } - fn read_i64(&mut self) -> Result { - match self.toml { - Some(Integer(i)) => { self.toml.take(); Ok(i) } - ref found => Err(self.mismatch("integer", found)), - } - } - fn read_i32(&mut self) -> Result { - self.read_i64().map(|i| i as i32) - } - fn read_i16(&mut self) -> Result { - self.read_i64().map(|i| i as i16) - } - fn read_i8(&mut self) -> Result { - self.read_i64().map(|i| i as i8) - } - fn read_bool(&mut self) -> Result { - match self.toml { - Some(Boolean(b)) => { self.toml.take(); Ok(b) } - ref found => Err(self.mismatch("bool", found)), - } - } - fn read_f64(&mut self) -> Result { - match self.toml { - Some(Float(f)) => Ok(f), - ref found => Err(self.mismatch("float", found)), - } - } - fn read_f32(&mut self) -> Result { - self.read_f64().map(|f| f as f32) - } - fn read_char(&mut self) -> Result { - 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 { - 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(&mut self, _name: &str, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - f(self) - } - - fn read_enum_variant(&mut self, names: &[&str], mut f: F) - -> Result - where F: FnMut(&mut Decoder, usize) -> Result - { - 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(&mut self, _a_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - f(self) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) - -> Result - where F: FnMut(&mut Decoder, usize) -> Result - { - panic!() - } - fn read_enum_struct_variant_field(&mut self, - _f_name: &str, - _f_idx: usize, - _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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(&mut self, f_name: &str, _f_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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(&mut self, tuple_len: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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(&mut self, a_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - self.read_seq_elt(a_idx, f) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - - // Specialized types: - fn read_option(&mut self, mut f: F) - -> Result - where F: FnMut(&mut Decoder, bool) -> Result - { - match self.toml { - Some(..) => f(self, true), - None => f(self, false), - } - } - - fn read_seq(&mut self, f: F) - -> Result - where F: FnOnce(&mut Decoder, usize) -> Result - { - 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(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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(&mut self, f: F) - -> Result - where F: FnOnce(&mut Decoder, usize) -> Result - { - 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(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - 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: &mut D) -> Result { - 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 = Decodable::decode(&mut d_bad1); - assert!(err1.is_err()); - let err2: Result = Decodable::decode(&mut d_bad2); - assert!(err2.is_err()); - } - - #[test] - fn array() { - #[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)] - struct Foo { a: Vec } - - 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>, - 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, - set: HashSet, - } - - 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, } - #[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 = 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 = 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 } - - 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 } - - 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> } - - 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 } - #[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 } - #[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> } - #[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()); - } -} -- cgit v1.2.3