toml 0.1.7

A native Rust encoder and decoder of TOML-formatted files and streams. Provides implementations of the standard Encodable/Decodable traits for TOML data to facilitate deserializing and serializing Rust structures.
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" as rustc_serialize;
/// extern crate toml;
///
/// # fn main() {
/// use toml::{Encoder, Value};
/// use rustc_serialize::Encodable;
///
/// #[deriving(RustcEncodable)]
/// struct MyStruct { foo: int, 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)]
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.
#[deriving(PartialEq)]
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.
#[deriving(PartialEq)]
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(uint),
    /// The nth map element was expected, but none was found.
    ExpectedMapElement(uint),
    /// 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
}

#[deriving(PartialEq, Show)]
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<Encoder, Error>>(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<Encoder, Error>>(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<Error> for Encoder {
    fn emit_nil(&mut self) -> Result<(), Error> { Ok(()) }
    fn emit_uint(&mut self, v: uint) -> 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_int(&mut self, v: int) -> 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(v.to_string().as_slice())
    }
    fn emit_str(&mut self, v: &str) -> Result<(), Error> {
        self.emit_value(Value::String(v.to_string()))
    }
    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: uint, _len: uint, f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        f(self)
    }
    fn emit_enum_variant_arg<F>(&mut self, _a_idx: uint, 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: uint,
                                   _len: uint,
                                   _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: uint,
                                         _f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        panic!()
    }
    fn emit_struct<F>(&mut self, _name: &str, _len: uint, 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: uint, f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        let old = mem::replace(&mut self.state, NextKey(f_name.to_string()));
        try!(f(self));
        if self.state != Start {
            return Err(NoValue)
        }
        self.state = old;
        Ok(())
    }
    fn emit_tuple<F>(&mut self, len: uint, f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_arg<F>(&mut self, idx: uint, 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: uint, _f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        unimplemented!()
    }
    fn emit_tuple_struct_arg<F>(&mut self, _f_idx: uint, _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: uint, 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: uint, f: F)
        -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        f(self)
    }
    fn emit_map<F>(&mut self, len: uint, 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: uint, mut f: F)
        -> Result<(), Error>
        where F: FnMut(&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: uint, 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<Decoder, DecodeError>>(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<Decoder, DecodeError>>(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(field.to_string()),
                    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<DecodeError> for Decoder {
    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_uint(&mut self) -> Result<uint, DecodeError> {
        self.read_i64().map(|i| i as uint)
    }
    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_int(&mut self) -> Result<int, DecodeError> {
        self.read_i64().map(|i| i as int)
    }
    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.as_slice().char_at(0),
            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, uint) -> Result<T, DecodeError>
    {
        let mut first_error = None;
        for i in range(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: uint, 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, uint) -> Result<T, DecodeError>
    {
        panic!()
    }
    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            _f_name: &str,
                                            _f_idx: uint,
                                            _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: uint, 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: uint, f: F)
        -> Result<T, DecodeError>
        where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
    {
        let field = f_name.to_string();
        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: uint, 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: uint, 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: uint, _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: uint, _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,uint) -> 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: uint, 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, uint) -> 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: uint, 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, _)) => {
                        f(&mut self.sub_decoder(Some(Value::String(key.to_string())),
                                                key.as_slice()))
                    }
                    None => Err(self.err(ExpectedMapKey(idx))),
                }
            }
            ref found => Err(self.mismatch("table", found)),
        }
    }
    fn read_map_elt_val<T, F>(&mut self, idx: uint, 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(err.to_string())
        }
    }
}

impl fmt::Show 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.as_slice(),
            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",
        }
    }
    fn detail(&self) -> Option<String> { Some(self.to_string()) }
}

impl fmt::Show 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" }
    fn detail(&self) -> Option<String> { Some(self.to_string()) }
}

#[cfg(test)]
mod tests {
    use std::collections::{BTreeMap, HashSet};
    use rustc_serialize::{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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: int }

        let v = Foo { a: 2 };
        assert_eq!(encode!(v), map! { a: Integer(2) });
        assert_eq!(v, decode!(Table(encode!(v))));
    }

    #[test]
    fn smoke_hyphen() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a_b: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: int, b: Bar }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(PartialEq, Show)]
        struct Range10(uint);
        impl<D: ::rustc_serialize::Decoder<E>, E> Decodable<D, E> for Range10 {
             fn decode(d: &mut D) -> Result<Range10, E> {
                 let x: uint = 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 int".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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Vec<int> }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: (int, int, int, int) }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo {
            a: Option<Box<Foo>>,
            b: Bar,
        }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Bar {
            a: String,
            b: f64,
        }

        let v = Foo {
            a: Some(box 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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo {
            map: BTreeMap<String, int>,
            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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo(int, 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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Vec<Bar>, }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Bar { a: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { bar: int }

        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!(e.to_string().as_slice(),
                           "expected a value of type `integer`, but \
                            found a value of type `float` for the key `bar`");
            }
        }
    }

    #[test]
    fn missing_errors() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { bar: int }

        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!(e.to_string().as_slice(),
                           "expected a value of type `integer` for the key `bar`");
            }
        }
    }

    #[test]
    fn parse_enum() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: E }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        enum E {
            Bar(int),
            Baz(f64),
            Last(Foo2),
        }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Bar }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Bar { a: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Bar }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Bar { a: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Vec<Bar> }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Bar { a: int }

        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Vec<Bar> }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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() {
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        struct Foo { a: Option<Vec<Bar>> }
        #[deriving(RustcEncodable, RustcDecodable, PartialEq, Show)]
        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());
    }
}