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};
pub struct Encoder {
pub toml: TomlTable,
state: EncoderState,
}
pub struct Decoder {
pub toml: Option<Value>,
cur_field: Option<String>,
}
#[allow(missing_copy_implementations)]
pub enum Error {
NeedsKey,
NoValue,
InvalidMapKeyLocation,
InvalidMapKeyType,
}
#[deriving(PartialEq)]
pub struct DecodeError {
pub field: Option<String>,
pub kind: DecodeErrorKind,
}
#[deriving(PartialEq)]
pub enum DecodeErrorKind {
ApplicationError(String),
ExpectedField( &'static str),
ExpectedType( &'static str, &'static str),
ExpectedMapKey(uint),
ExpectedMapElement(uint),
NoEnumVariants,
NilTooLong
}
#[deriving(PartialEq, Show)]
enum EncoderState {
Start,
NextKey(String),
NextArray(Vec<Value>),
NextMapKey,
}
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)
}
pub fn encode_str<T: rustc_serialize::Encodable<Encoder, Error>>(t: &T) -> String {
format!("{}", encode(t))
}
impl Encoder {
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) => {
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)
}
}
pub fn decode<T: rustc_serialize::Decodable<Decoder, DecodeError>>(toml: Value)
-> Option<T>
{
rustc_serialize::Decodable::decode(&mut Decoder::new(toml)).ok()
}
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 {
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
}
}
}
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!()
}
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)) => {
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());
}
}