aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--Cargo.toml8
-rw-r--r--src/decoder/mod.rs205
-rw-r--r--src/decoder/rustc_serialize.rs311
-rw-r--r--src/encoder/mod.rs210
-rw-r--r--src/encoder/rustc_serialize.rs689
-rw-r--r--src/lib.rs70
-rw-r--r--src/serialization.rs1279
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: |
diff --git a/Cargo.toml b/Cargo.toml
index cf33dc1..102f63d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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);
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index da2ddbc..0196fbc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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());
- }
-}