use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::mem;
use {Value, Table};
#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;
#[derive(Default, Debug)]
pub struct Encoder {
pub toml: Table,
state: State,
}
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub enum Error {
NeedsKey,
NoValue,
InvalidMapKeyLocation,
InvalidMapKeyType,
Custom(String),
}
#[derive(Debug)]
pub struct EncoderState {
inner: State,
}
#[derive(PartialEq, Debug)]
enum State {
Start,
NextKey(String),
NextArray(Vec<Value>),
NextMapKey,
}
impl Default for State {
fn default() -> State { State::Start }
}
impl Encoder {
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) => {
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_begin(&mut self) -> Result<State, Error> {
Ok(mem::replace(&mut self.state, State::NextArray(Vec::new())))
}
fn seq_end(&mut self, old: State) -> Result<(), Error> {
match mem::replace(&mut self.state, old) {
State::NextArray(v) => self.emit_value(Value::Array(v)),
_ => unreachable!(),
}
}
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),
}
}
}
#[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)
}
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
let mut e = Encoder::new();
t.serialize(&mut e).unwrap();
Value::Table(e.toml)
}
#[cfg(feature = "rustc-serialize")]
pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
encode(t).to_string()
}
#[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, "no 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"),
Error::Custom(ref s) => write!(f, "custom error: {}", s),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str { "TOML encoding error" }
}