toml_edit 0.1.1

Yet another format-preserving TOML parser.
Documentation
use value::{Array, DateTime, InlineTable, Value};
use table::{Item, KeyValuePairs, TableKeyValue};
use decor::{Decor, Formatted, InternalString, Repr};
use key::Key;
use std::iter::FromIterator;
use parser::strings;
use parser::TomlError;
use combine::{self, Parser};


pub(crate) fn decorate_array(array: &mut Array) {
    for (i, val) in array
        .values
        .iter_mut()
        .filter_map(|i| i.as_value_mut())
        .enumerate()
    {
        // [value1, value2, value3]
        if i > 0 {
            decorate(val, " ", "");
        } else {
            decorate(val, "", "");
        }
    }
}

pub(crate) fn decorate_inline_table(table: &mut InlineTable) {
    let n = table.len();
    for (i, (key, value)) in table
        .items
        .iter_mut()
        .filter(|&(_, ref kv)| kv.value.is_value())
        .map(|(_, kv)| (&mut kv.key, kv.value.as_value_mut().unwrap()))
        .enumerate()
    {
        // { key1 = value1, key2 = value2 }
        key.decor.prefix = InternalString::from(" ");
        key.decor.suffix = InternalString::from(" ");
        if i == n - 1 {
            decorate(value, " ", " ");
        } else {
            decorate(value, " ", "");
        }
    }
}

pub(crate) fn decorate(value: &mut Value, prefix: &str, suffix: &str) {
    let decor = match *value {
        Value::Integer(ref mut f) => &mut f.repr.decor,
        Value::String(ref mut f) => &mut f.repr.decor,
        Value::Float(ref mut f) => &mut f.repr.decor,
        Value::DateTime(ref mut f) => &mut f.repr.decor,
        Value::Boolean(ref mut f) => &mut f.repr.decor,
        Value::Array(ref mut a) => &mut a.decor,
        Value::InlineTable(ref mut t) => &mut t.decor,
    };
    decor.prefix = InternalString::from(prefix);
    decor.suffix = InternalString::from(suffix);
}

pub fn decorated(mut value: Value, prefix: &str, suffix: &str) -> Value {
    {
        decorate(&mut value, prefix, suffix);
    }
    value
}

pub(crate) fn value(mut val: Value, raw: &str) -> Value {
    match val {
        Value::Integer(ref mut f) => {
            f.repr.raw_value = InternalString::from(raw);
        }
        Value::String(ref mut f) => {
            f.repr.raw_value = InternalString::from(raw);
        }
        Value::Float(ref mut f) => {
            f.repr.raw_value = InternalString::from(raw);
        }
        Value::DateTime(ref mut f) => {
            f.repr.raw_value = InternalString::from(raw);
        }
        Value::Boolean(ref mut f) => {
            f.repr.raw_value = InternalString::from(raw);
        }
        _ => {}
    };
    decorate(&mut val, "", "");
    val
}

pub(crate) fn to_key_value(key: &str, mut value: Value) -> TableKeyValue {
    decorate(&mut value, " ", "");
    to_table_key_value(key, Item::Value(value))
}

pub(crate) fn to_table_key_value(key: &str, value: Item) -> TableKeyValue {
    TableKeyValue {
        key: key_repr(key),
        value: value,
    }
}

pub(crate) fn key_repr(raw: &str) -> Repr {
    Repr {
        decor: Decor {
            prefix: InternalString::from(""),
            suffix: InternalString::from(" "),
        },
        raw_value: raw.into(),
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Integer(Formatted::new(
            i,
            Repr::new("".to_string(), i.to_string(), "".to_string()),
        ))
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Value::Float(Formatted::new(
            f,
            Repr::new("".to_string(), f.to_string(), "".to_string()),
        ))
    }
}

macro_rules! try_parse {
    ($s:expr, $p:expr) => (
        {
            let result = $p.parse(combine::State::new($s));
            match result {
                Ok((_, ref rest)) if !rest.input.is_empty() => {
                    Err(TomlError::from_unparsed(rest.positioner, $s))
                }
                Ok((s, _)) => Ok(s),
                Err(e) => Err(TomlError::new(e, $s)),
            }
        }
    );
}

// TODO: clean this mess
fn parse_string_guess_delimiters(s: &str) -> (InternalString, InternalString) {
    let basic = format!("\"{}\"", s);
    let literal = format!("'{}'", s);
    let ml_basic = format!("\"\"\"{}\"\"\"", s);
    let ml_literal = format!("'''{}'''", s);
    if let Ok(r) = try_parse!(s, strings::string()) {
        return (r, s.into());
    } else if let Ok(r) = try_parse!(&basic[..], strings::basic_string()) {
        return (r, basic);
    } else if let Ok(r) = try_parse!(&literal[..], strings::literal_string()) {
        return (r.into(), literal.clone());
    } else if let Ok(r) = try_parse!(&ml_basic[..], strings::ml_basic_string()) {
        return (r, ml_literal);
    } else {
        try_parse!(&ml_literal[..], strings::ml_literal_string())
            .map(|r| (r, ml_literal))
            .unwrap_or_else(|e| panic!("toml string parse error: {}, {}", e, s))
    }
}

impl<'b> From<&'b str> for Value {
    fn from(s: &'b str) -> Self {
        let (value, raw) = parse_string_guess_delimiters(s);
        Value::String(Formatted::new(
            value,
            Repr::new("".to_string(), raw, "".to_string()),
        ))
    }
}

impl From<InternalString> for Value {
    fn from(s: InternalString) -> Self {
        Value::from(s.as_ref())
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Value::Boolean(Formatted::new(
            b,
            Repr::new("", if b { "true" } else { "false" }, ""),
        ))
    }
}

impl From<DateTime> for Value {
    fn from(d: DateTime) -> Self {
        let s = d.to_string();
        Value::DateTime(Formatted::new(
            d,
            Repr::new("".to_string(), s, "".to_string()),
        ))
    }
}

impl<V: Into<Value>> FromIterator<V> for Value {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = V>,
    {
        let v = iter.into_iter().map(|a| Item::Value(a.into()));
        let mut array = Array {
            values: v.collect(),
            ..Default::default()
        };
        decorate_array(&mut array);
        Value::Array(array)
    }
}

pub(crate) fn to_key_value_pairs<'k, K, V, I>(iter: I) -> KeyValuePairs
where
    K: Into<&'k Key>,
    V: Into<Value>,
    I: IntoIterator<Item = (K, V)>,
{
    let v = iter.into_iter().map(|(a, b)| {
        let s: &Key = a.into();
        (s.get().into(), to_key_value(s.raw(), b.into()))
    });
    KeyValuePairs::from_iter(v)
}

impl<'k, K: Into<&'k Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
    fn from_iter<I>(iter: I) -> Self
    where
        I: IntoIterator<Item = (K, V)>,
    {
        let mut table = InlineTable {
            items: to_key_value_pairs(iter),
            ..Default::default()
        };
        decorate_inline_table(&mut table);
        Value::InlineTable(table)
    }
}