From f66d8bcf33530c858a502bfa170f2383a8cbc204 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 29 Jan 2017 16:53:20 -0800 Subject: Rewrite crate with serde support from ground up This commit completely rewrites this crate from the ground up, supporting serde at the lowest levels as I believe serde support was intended to do. This is a major change from the previous versions of this crate, with a summary of changes being: * Serialization directly to TOML is now supported without going through a `Value` first. * Deserialization directly from TOML is now supported without going through a `Value`. Note that due to the TOML format some values still are buffered in intermediate memory, but overall this should be at a minimum now. * The API of `Value` was overhauled to match the API of `serde_json::Value`. The changes here were to: * Add `is_*` accessors * Add `get` and `get_mut` for one-field lookups. * Implement panicking lookups through `Index` The old `index` methods are now gone in favor of `get` and `Index` implementations. * A `Datetime` type has been added to represent a TOML datetime in a first-class fashion. Currently this type provides no accessors other than a `Display` implementation, but the idea is that this will grow support over time for decomposing the date. * Support for the `rustc-serialize` crate has been dropped, that'll stay on the 0.2 and 0.1 release trains. * This crate no longer supports the detection of unused fields, for that though you can use the `serde_ignored` crate on crates.io --- src/decoder/mod.rs | 240 ----------------------------------------------------- 1 file changed, 240 deletions(-) delete mode 100644 src/decoder/mod.rs (limited to 'src/decoder/mod.rs') diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs deleted file mode 100644 index 51a9ea2..0000000 --- a/src/decoder/mod.rs +++ /dev/null @@ -1,240 +0,0 @@ -use std::error; -use std::fmt; - -use std::collections::{btree_map, BTreeMap}; -use std::iter::Peekable; - -use Value; -use self::DecodeErrorKind::*; - -#[cfg(feature = "rustc-serialize")] mod rustc_serialize; -#[cfg(feature = "serde")] mod serde; - -/// 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, - - // These aren't used if serde is in use - #[cfg_attr(feature = "serde", allow(dead_code))] - cur_map: Peekable>, - #[cfg_attr(feature = "serde", allow(dead_code))] - leftover_map: ::Table, -} - -/// 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 */ Option<&'static str>), - /// A field was found, but it was not an expected one. - UnknownField, - /// 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, - /// A custom error was generated when decoding. - CustomError(String), - /// The end of the TOML input was reached too soon - EndOfStream, - /// Produced by serde ... - InvalidType(&'static str), -} - -/// 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(toml: Value) -> Option { - ::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(toml: Value) -> Option { - ::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 -/// returned. -/// -/// If more fine-grained errors are desired, these steps should be driven -/// manually. -#[cfg(feature = "rustc-serialize")] -pub fn decode_str(s: &str) -> Option { - ::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 -/// returned. -/// -/// 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(s: &str) -> Option { - ::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::new_empty(Some(toml), None) - } - - fn sub_decoder(&self, toml: Option, field: &str) -> Decoder { - let cur_field = if field.is_empty() { - self.cur_field.clone() - } else { - match self.cur_field { - None => Some(field.to_string()), - Some(ref s) => Some(format!("{}.{}", s, field)) - } - }; - Decoder::new_empty(toml, cur_field) - } - - fn new_empty(toml: Option, cur_field: Option) -> Decoder { - Decoder { - toml: toml, - cur_field: cur_field, - leftover_map: BTreeMap::new(), - cur_map: BTreeMap::new().into_iter().peekable(), - } - } - - 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(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"), - } - } - UnknownField => write!(f, "unknown field"), - ExpectedType(expected, found) => { - fn humanize(s: &str) -> String { - if s == "section" { - "a section".to_string() - } 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") - } - InvalidType(s) => { - write!(f, "invalid type: {}", s) - } - CustomError(ref s) => { - write!(f, "custom error: {}", s) - } - }); - 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", - UnknownField => "found an unknown 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", - InvalidType(..) => "invalid type", - CustomError(..) => "custom error", - } - } -} -- cgit v1.2.3