Repository: toml-rs/toml (language: rust)

Issue:
API revamp
Current API is not easy to use. Inserting into the document requires borrowing the root table.


Discussion / hints:

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 1b3f4846..cfca5e4f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,7 +32,7 @@ matrix:
     - rust: nightly
 
   include:
-  - rust: nightly-2017-07-25
+  - rust: nightly-2017-12-08
     env:
       global:
         - RUSTFLAGS="-C link-dead-code"
@@ -47,8 +47,8 @@ matrix:
           - libiberty-dev
 
     before_script:
-    - cargo install clippy --vers 0.0.145 || true
-    - cargo install rustfmt-nightly --vers 0.2.1 || true
+    - bash -c '[ "$(cargo clippy --version 2>/dev/null)" == "0.0.175" ] || cargo install clippy --vers 0.0.175 --force'
+    - bash -c '[ "$(rustfmt --version 2>/dev/null)" == "0.2.17-nightly ( )" ] || cargo install rustfmt-nightly --vers 0.2.17 --force'
 
     script:
     - cargo clippy -- -D warnings -Z no-trans
diff --git a/Cargo.toml b/Cargo.toml
index a537c3c4..1dd85db6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,10 +16,8 @@ appveyor = { repository = "ordian/toml_edit" }
 
 [dependencies]
 chrono = "0.4"
-intrusive-collections = "0.6"
 linked-hash-map = "0.4"
-typed-arena = "1.3"
-combine = "3.0.0-alpha.2"
+combine = "=3.0.0-alpha.2"
 
 [dev-dependencies]
 serde_json = "1.0"
diff --git a/README.md b/README.md
index 753e59e9..fbeaba22 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@
 
 
 This crate allows you to parse and modify toml
-documents, while *mostly* preserving comments, spaces and
-relative order or items.
+documents, while preserving comments, spaces* and
+relative order* or items.
 
-Things it does not preserve include:
+*Things it does not preserve:
 1. Spaces in headers, e.g. `[ ' a ' .  b ]` will be represented as [' a '.b]
 2. Children tables before parent table (tables are reordered).
 3. Scattered array of tables (tables are reordered).
@@ -24,16 +24,24 @@ Things it does not preserve include:
 ```rust
 extern crate toml_edit;
 
-use toml_edit::Document;
+use toml_edit::{Document, value};
 
 fn main() {
     let toml = r#"
-      "hello" = 'toml!' # comment
-      ['a'.b]
+"hello" = 'toml!' # comment
+['a'.b]
     "#;
-    let doc = toml.parse::<Document>();
-    assert!(doc.is_ok());
-    assert_eq!(doc.unwrap().to_string(), toml);
+    let mut doc = toml.parse::<Document>().expect("invalid doc");
+    assert_eq!(doc.to_string(), toml);
+    doc["a"]["b"]["c"]["d"] = value("hello");
+    // autoformat inline table a.b.c
+    doc["a"]["b"]["c"].as_value_mut().and_then(|v| v.as_inline_table_mut().map(|t| t.fmt()));
+    let expected = r#"
+"hello" = 'toml!' # comment
+['a'.b]
+c = { d = "hello" }
+    "#;
+    assert_eq!(doc.to_string(), expected);
 }
 ```
 
diff --git a/fuzz/run.sh b/fuzz/run.sh
index 501cf528..d415999a 100755
--- a/fuzz/run.sh
+++ b/fuzz/run.sh
@@ -2,7 +2,9 @@
 
 set -e
 
-wget https://github.com/rust-fuzz/targets/raw/master/run-fuzzer.sh -O run-fuzzer.sh
+if [ ! -f run-fuzzer.sh ]; then
+    wget https://github.com/rust-fuzz/targets/raw/master/run-fuzzer.sh -O run-fuzzer.sh
+fi
 
 crate="$(dirname $0)"
 target="parse_document"
diff --git a/src/array_of_tables.rs b/src/array_of_tables.rs
index 19b72b27..c7315853 100644
--- a/src/array_of_tables.rs
+++ b/src/array_of_tables.rs
@@ -1,33 +1,36 @@
-use table::Table;
+use table::{Item, Table};
 
 /// Type representing a TOML array of tables
 #[derive(Clone, Debug, Default)]
 pub struct ArrayOfTables {
-    pub(crate) values: Vec<Table>,
+    // always Vec<Item::Table>
+    pub(crate) values: Vec<Item>,
 }
 
+type ArrayOfTablesIter<'a> = Box<Iterator<Item = &'a Table> + 'a>;
+
 impl ArrayOfTables {
     pub fn new() -> Self {
         Default::default()
     }
 
     /// Returns an iterator over tables
-    pub fn iter<'a>(&'a self) -> Box<Iterator<Item = &'a Table> + 'a> {
-        Box::new(self.values.iter())
+    pub fn iter(&self) -> ArrayOfTablesIter {
+        Box::new(self.values.iter().filter_map(Item::as_table))
     }
 
     /// Returns an optional reference to the table
     pub fn get(&self, index: usize) -> Option<&Table> {
-        self.values.get(index)
+        self.values.get(index).and_then(Item::as_table)
     }
 
     /// Returns an optional mutable reference to the table
     pub fn get_mut(&mut self, index: usize) -> Option<&mut Table> {
-        self.values.get_mut(index)
+        self.values.get_mut(index).and_then(Item::as_table_mut)
     }
 
     pub fn append(&mut self, table: Table) -> &mut Table {
-        self.values.push(table);
+        self.values.push(Item::Table(table));
         let i = self.len() - 1;
         self.get_mut(i).unwrap()
     }
@@ -41,7 +44,7 @@ impl ArrayOfTables {
     }
 
     pub fn len(&self) -> usize {
-        self.values.len()
+        self.values.iter().filter(|i| i.is_table()).count()
     }
 
     pub fn is_empty(&self) -> bool {
diff --git a/src/display.rs b/src/display.rs
index c0242881..504d4bee 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -1,8 +1,8 @@
 use std::fmt::{Display, Formatter, Result};
-use value::{Array, DateTime, InlineTable, KeyValue, Value};
+use value::{Array, DateTime, InlineTable, Value};
 use decor::{Formatted, Repr};
 use document::Document;
-use table::{Container, Table};
+use table::{Item, Table};
 use std::cell::{Cell, RefCell};
 
 impl Display for Repr {
@@ -51,7 +51,7 @@ impl Display for Value {
 impl Display for Array {
     fn fmt(&self, f: &mut Formatter) -> Result {
         write!(f, "{}[", self.decor.prefix)?;
-        join(f, self.values.iter(), ",")?;
+        join(f, self.iter(), ",")?;
         if self.trailing_comma {
             write!(f, ",")?;
         }
@@ -60,17 +60,21 @@ impl Display for Array {
     }
 }
 
-impl Display for KeyValue {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        write!(f, "{}={}", self.key, self.value)
-    }
-}
-
 impl Display for InlineTable {
     fn fmt(&self, f: &mut Formatter) -> Result {
         write!(f, "{}{{", self.decor.prefix)?;
         write!(f, "{}", self.preamble)?;
-        join(f, self.key_value_pairs.values(), ",")?;
+        for (i, (key, value)) in self.items
+            .iter()
+            .filter(|&(_, kv)| kv.value.is_value())
+            .map(|(_, kv)| (&kv.key, kv.value.as_value().unwrap()))
+            .enumerate()
+        {
+            if i > 0 {
+                write!(f, ",")?;
+            }
+            write!(f, "{}={}", key, value)?;
+        }
         write!(f, "}}{}", self.decor.suffix)
     }
 }
@@ -84,17 +88,18 @@ impl<'a> Display for TableFormatState<'a> {
     fn fmt(&self, f: &mut Formatter) -> Result {
         let table = self.table.get();
 
-        join(f, table.key_value_pairs.values(), "\n")?;
-        if !table.key_value_pairs.is_empty() {
-            write!(f, "\n")?;
+        for kv in table.items.values() {
+            if let Item::Value(ref value) = kv.value {
+                write!(f, "{}={}\n", kv.key, value)?;
+            }
         }
 
-        for &(ref name, ref c) in table.containers.values() {
-            match *c {
-                Container::Table(ref t) => {
-                    self.path.borrow_mut().push(name);
+        for kv in table.items.values() {
+            match kv.value {
+                Item::Table(ref t) => {
+                    self.path.borrow_mut().push(&kv.key.raw_value);
                     self.table.set(t);
-                    if !t.implicit {
+                    if !(t.implicit && t.values_len() == 0) {
                         write!(f, "{}[", t.decor.prefix)?;
                         write!(f, "{}", self.path.borrow().join("."))?;
                         write!(f, "]{}\n", t.decor.suffix)?;
@@ -103,9 +108,9 @@ impl<'a> Display for TableFormatState<'a> {
                     self.table.set(table);
                     self.path.borrow_mut().pop();
                 }
-                Container::Array(ref a) => {
-                    self.path.borrow_mut().push(name);
-                    for t in &a.values {
+                Item::ArrayOfTables(ref a) => {
+                    self.path.borrow_mut().push(&kv.key.raw_value);
+                    for t in a.iter() {
                         self.table.set(t);
                         write!(f, "{}[[", t.decor.prefix)?;
                         write!(f, "{}", self.path.borrow().join("."))?;
@@ -115,19 +120,26 @@ impl<'a> Display for TableFormatState<'a> {
                     self.table.set(table);
                     self.path.borrow_mut().pop();
                 }
+                _ => {}
             }
         }
         Ok(())
     }
 }
 
-impl Display for Document {
+impl Display for Table {
     fn fmt(&self, f: &mut Formatter) -> Result {
         let state = TableFormatState {
             path: RefCell::new(Vec::new()),
-            table: Cell::new(&self.root),
+            table: Cell::new(self),
         };
-        write!(f, "{}", state)?;
+        write!(f, "{}", state)
+    }
+}
+
+impl Display for Document {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        write!(f, "{}", self.root)?;
         write!(f, "{}", self.trailing)
     }
 }
diff --git a/src/document.rs b/src/document.rs
index 7a782f44..dd087d27 100644
--- a/src/document.rs
+++ b/src/document.rs
@@ -1,5 +1,5 @@
 use std::str::FromStr;
-use table::{Table, TableChild};
+use table::{Iter, Table};
 use decor::InternalString;
 use parser;
 
@@ -18,7 +18,7 @@ impl Document {
         Default::default()
     }
 
-    pub fn iter<'a>(&'a self) -> Box<Iterator<Item = (&'a str, TableChild<'a>)> + 'a> {
+    pub fn iter(&self) -> Iter {
         self.root.iter()
     }
 }
diff --git a/src/formatted.rs b/src/formatted.rs
index 74a5c726..f535edf3 100644
--- a/src/formatted.rs
+++ b/src/formatted.rs
@@ -1,11 +1,17 @@
-use value::{Array, DateTime, InlineTable, KeyValue, KeyValuePairs, Value};
+use value::{Array, DateTime, InlineTable, Value};
+use table::{Item, KeyValuePairs, TableKeyValue};
 use decor::{Decor, Formatted, InternalString, Repr};
 use key::Key;
 use std::iter::FromIterator;
 
 
 pub(crate) fn decorate_array(array: &mut Array) {
-    for (i, val) in array.values.iter_mut().enumerate() {
+    for (i, val) in array
+        .values
+        .iter_mut()
+        .filter_map(|i| i.as_value_mut())
+        .enumerate()
+    {
         // [value1, value2, value3]
         if i > 0 {
             decorate(val, " ", "");
@@ -16,15 +22,21 @@ pub(crate) fn decorate_array(array: &mut Array) {
 }
 
 pub(crate) fn decorate_inline_table(table: &mut InlineTable) {
-    let n = table.key_value_pairs.len();
-    for (i, (_, kv)) in table.key_value_pairs.iter_mut().enumerate() {
+    let n = table.len();
+    for (i, (mut key, mut 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 }
-        kv.key.decor.prefix = InternalString::from(" ");
-        kv.key.decor.suffix = InternalString::from(" ");
+        key.decor.prefix = InternalString::from(" ");
+        key.decor.suffix = InternalString::from(" ");
         if i == n - 1 {
-            decorate(&mut kv.value, " ", " ");
+            decorate(value, " ", " ");
         } else {
-            decorate(&mut kv.value, " ", "");
+            decorate(value, " ", "");
         }
     }
 }
@@ -43,7 +55,7 @@ pub(crate) fn decorate(value: &mut Value, prefix: &str, suffix: &str) {
     decor.suffix = InternalString::from(suffix);
 }
 
-pub(crate) fn decorated(mut value: Value, prefix: &str, suffix: &str) -> Value {
+pub fn decorated(mut value: Value, prefix: &str, suffix: &str) -> Value {
     {
         decorate(&mut value, prefix, suffix);
     }
@@ -73,20 +85,28 @@ pub(crate) fn value(mut val: Value, raw: &str) -> Value {
     val
 }
 
-pub(crate) fn to_key_value(key: &str, mut value: Value) -> KeyValue {
+pub(crate) fn to_key_value(key: &str, mut value: Value) -> TableKeyValue {
     decorate(&mut value, " ", "");
-    KeyValue {
-        key: Repr {
-            decor: Decor {
-                prefix: InternalString::from(""),
-                suffix: InternalString::from(" "),
-            },
-            raw_value: key.into(),
-        },
+    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(
@@ -145,7 +165,7 @@ impl<V: Into<Value>> FromIterator<V> for Value {
     where
         I: IntoIterator<Item = V>,
     {
-        let v = iter.into_iter().map(|a| a.into());
+        let v = iter.into_iter().map(|a| Item::Value(a.into()));
         let mut array = Array {
             values: v.collect(),
             ..Default::default()
@@ -174,7 +194,7 @@ impl<'k, K: Into<&'k Key>, V: Into<Value>> FromIterator<(K, V)> for Value {
         I: IntoIterator<Item = (K, V)>,
     {
         let mut table = InlineTable {
-            key_value_pairs: to_key_value_pairs(iter),
+            items: to_key_value_pairs(iter),
             ..Default::default()
         };
         decorate_inline_table(&mut table);
diff --git a/src/index.rs b/src/index.rs
new file mode 100644
index 00000000..8266be2f
--- /dev/null
+++ b/src/index.rs
@@ -0,0 +1,159 @@
+use std::ops;
+use table::{value, Item, Table};
+use value::{InlineTable, Value};
+use formatted::to_table_key_value;
+use document::Document;
+
+// copied from
+// https://github.com/serde-rs/json/blob/master/src/value/index.rs
+
+// Prevent users from implementing the Index trait.
+mod private {
+    pub trait Sealed {}
+    impl Sealed for usize {}
+    impl Sealed for str {}
+    impl Sealed for String {}
+    impl<'a, T: ?Sized> Sealed for &'a T
+    where
+        T: Sealed,
+    {
+    }
+}
+
+pub trait Index: private::Sealed {
+    /// Return `Option::None` if the key is not already in the array or table.
+    #[doc(hidden)]
+    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item>;
+
+    /// Panic if array index out of bounds. If key is not already in the table,
+    /// insert it with a value of `Item::None`. Panic if `v` has a type that cannot be
+    /// indexed into, except if `v` is `Item::None` then it can be treated as an empty
+    /// inline table.
+    #[doc(hidden)]
+    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item;
+}
+
+impl Index for usize {
+    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
+        match *v {
+            Item::ArrayOfTables(ref aot) => aot.values.get(*self),
+            Item::Value(ref a) if a.is_array() => a.as_array().unwrap().values.get(*self),
+            _ => None,
+        }
+    }
+    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
+        match *v {
+            Item::ArrayOfTables(ref mut vec) => {
+                vec.values.get_mut(*self).expect("index out of bounds")
+            }
+            Item::Value(ref mut a) if a.is_array() => a.as_array_mut()
+                .unwrap()
+                .values
+                .get_mut(*self)
+                .expect("index out of bounds"),
+            _ => panic!("cannot access index {} in {:?}", self, v),
+        }
+    }
+}
+
+impl Index for str {
+    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
+        match *v {
+            Item::Table(ref t) => t.get(self),
+            Item::Value(ref v) if v.is_inline_table() => v.as_inline_table()
+                .and_then(|t| t.items.get(self).map(|kv| &kv.value)),
+            _ => None,
+        }
+    }
+    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
+        if let Item::None = *v {
+            let mut t = InlineTable::default();
+            t.items
+                .insert(self.to_owned(), to_table_key_value(self, Item::None));
+            *v = value(Value::InlineTable(t));
+        }
+        match *v {
+            Item::Table(ref mut t) => t.entry(self).or_insert(Item::None),
+            Item::Value(ref mut v) if v.is_inline_table() => {
+                &mut v.as_inline_table_mut()
+                    .unwrap()
+                    .items
+                    .entry(self.to_owned())
+                    .or_insert(to_table_key_value(self, Item::None))
+                    .value
+            }
+            _ => panic!("cannot access key {} in {:?}", self, v),
+        }
+    }
+}
+
+impl Index for String {
+    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
+        self[..].index(v)
+    }
+    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
+        self[..].index_or_insert(v)
+    }
+}
+
+impl<'a, T: ?Sized> Index for &'a T
+where
+    T: Index,
+{
+    fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> {
+        (**self).index(v)
+    }
+    fn index_or_insert<'v>(&self, v: &'v mut Item) -> &'v mut Item {
+        (**self).index_or_insert(v)
+    }
+}
+
+impl<I> ops::Index<I> for Item
+where
+    I: Index,
+{
+    type Output = Item;
+
+    fn index(&self, index: I) -> &Item {
+        static NONE: Item = Item::None;
+        index.index(self).unwrap_or(&NONE)
+    }
+}
+
+impl<I> ops::IndexMut<I> for Item
+where
+    I: Index,
+{
+    fn index_mut(&mut self, index: I) -> &mut Item {
+        index.index_or_insert(self)
+    }
+}
+
+impl<'s> ops::Index<&'s str> for Table {
+    type Output = Item;
+
+    fn index(&self, key: &'s str) -> &Item {
+        static NONE: Item = Item::None;
+        self.get(key).unwrap_or(&NONE)
+    }
+}
+
+impl<'s> ops::IndexMut<&'s str> for Table {
+    fn index_mut(&mut self, key: &'s str) -> &mut Item {
+        self.entry(key).or_insert(Item::None)
+    }
+}
+
+impl<'s> ops::Index<&'s str> for Document {
+    type Output = Item;
+
+    fn index(&self, key: &'s str) -> &Item {
+        self.root.index(key)
+    }
+}
+
+impl<'s> ops::IndexMut<&'s str> for Document {
+    fn index_mut(&mut self, key: &'s str) -> &mut Item {
+        self.root.index_mut(key)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index dbd30866..e3ef8866 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,21 +14,30 @@
 //! ```rust
 //! extern crate toml_edit;
 //!
-//! use toml_edit::Document;
+//! use toml_edit::{Document, value};
 //!
 //! fn main() {
 //!     let toml = r#"
-//!       "hello" = 'toml!' # comment
-//!       ['a'.b]
+//! "hello" = 'toml!' # comment
+//! ['a'.b]
 //!     "#;
-//!     let doc = toml.parse::<Document>();
-//!     assert!(doc.is_ok());
-//!     assert_eq!(doc.unwrap().to_string(), toml);
+//!     let mut doc = toml.parse::<Document>().expect("invalid doc");
+//!     assert_eq!(doc.to_string(), toml);
+//!     // let's add a new key/value pair
+//!     doc["a"]["b"]["c"]["d"] = value("hello");
+//!     // autoformat inline table a.b.c
+//!     doc["a"]["b"]["c"].as_value_mut().and_then(|v| v.as_inline_table_mut().map(|t| t.fmt()));
+//!     let expected = r#"
+//! "hello" = 'toml!' # comment
+//! ['a'.b]
+//! c = { d = "hello" }
+//!     "#;
+//!     assert_eq!(doc.to_string(), expected);
 //! }
 //! ```
+extern crate chrono;
 #[macro_use]
 extern crate combine;
-extern crate chrono;
 extern crate linked_hash_map;
 
 
@@ -41,10 +50,11 @@ mod key;
 mod array_of_tables;
 mod table;
 mod document;
+mod index;
 
 pub use value::{Array, InlineTable, Value};
 pub use key::Key;
 pub use parser::TomlError;
-pub use table::{Iter, IterMut, Table, TableChild, TableChildMut, TableEntry};
+pub use table::{array, table, value, Item, Iter, Table};
 pub use array_of_tables::ArrayOfTables;
 pub use document::Document;
diff --git a/src/parser/array.rs b/src/parser/array.rs
index 50f08717..8adb2be3 100644
--- a/src/parser/array.rs
+++ b/src/parser/array.rs
@@ -26,11 +26,7 @@ fn array_from_vec(v: Vec<Value>, comma: bool, trailing: &str) -> Result<Array, C
             got: format!("{:?}", val.get_type()),
             expected: format!("{:?}", array.value_type()),
         });
-        if !array.push_value(
-            val,
-            /* decorate = */
-            false,
-        ) {
+        if !array.push_value(val, /* decorate = */ false) {
             return err;
         }
     }
diff --git a/src/parser/document.rs b/src/parser/document.rs
index 4894d515..93de9355 100644
--- a/src/parser/document.rs
+++ b/src/parser/document.rs
@@ -12,7 +12,7 @@ use parser::table::table;
 use parser::inline_table::KEYVAL_SEP;
 use decor::{InternalString, Repr};
 use document::Document;
-use value::KeyValue;
+use table::{Item, TableKeyValue};
 use formatted::decorated;
 use std::mem;
 use std::cell::RefCell;
@@ -80,7 +80,7 @@ parser!{
 
 // keyval = key keyval-sep val
 parser!{
-    fn parse_keyval['a, I]()(I) -> (InternalString, KeyValue)
+    fn parse_keyval['a, I]()(I) -> (InternalString, TableKeyValue)
         where
         [I: RangeStream<Range = &'a str, Item = char>,]
     {
@@ -94,9 +94,9 @@ parser!{
             let ((raw, key), suf) = k;
             (
                 key,
-                KeyValue {
+                TableKeyValue {
                     key: Repr::new("", raw, suf),
-                    value: v,
+                    value: Item::Value(v),
                 }
             )
         })
@@ -148,7 +148,7 @@ impl TomlParser {
         self.document.trailing.push_str(e);
     }
 
-    fn on_keyval(&mut self, key: InternalString, mut kv: KeyValue) -> Result<(), CustomError> {
+    fn on_keyval(&mut self, key: InternalString, mut kv: TableKeyValue) -> Result<(), CustomError> {
         let table = unsafe { &mut *self.current_table };
 
         let prefix = mem::replace(&mut self.document.trailing, InternalString::new());
@@ -156,11 +156,15 @@ impl TomlParser {
 
         if table.contains_key(&key) {
             Err(CustomError::DuplicateKey {
-                key: key.into(),
+                key: key,
                 table: "<unknown>".into(), // TODO: get actual table name
             })
         } else {
-            table.key_value_pairs.insert(key, kv);
+            let tkv = TableKeyValue {
+                key: kv.key,
+                value: kv.value,
+            };
+            table.items.insert(key, tkv);
             Ok(())
         }
     }
diff --git a/src/parser/inline_table.rs b/src/parser/inline_table.rs
index b4cee5f3..07a88bd5 100644
--- a/src/parser/inline_table.rs
+++ b/src/parser/inline_table.rs
@@ -5,8 +5,9 @@ use parser::errors::CustomError;
 use parser::trivia::ws;
 use parser::key::key;
 use parser::value::value;
-use value::{InlineTable, KeyValue};
+use value::InlineTable;
 use decor::{InternalString, Repr};
+use table::{Item, TableKeyValue};
 use formatted::decorated;
 
 // ;; Inline Table
@@ -19,7 +20,7 @@ parse!(inline_table() -> InlineTable, {
 
 fn table_from_pairs(
     preamble: &str,
-    v: Vec<(InternalString, KeyValue)>,
+    v: Vec<(InternalString, TableKeyValue)>,
 ) -> Result<InlineTable, CustomError> {
     let mut table = InlineTable::default();
     table.preamble = InternalString::from(preamble);
@@ -27,11 +28,11 @@ fn table_from_pairs(
     for (k, kv) in v {
         if table.contains_key(&k) {
             return Err(CustomError::DuplicateKey {
-                key: k.into(),
+                key: k,
                 table: "inline".into(),
             });
         }
-        table.key_value_pairs.insert(k, kv);
+        table.items.insert(k, kv);
     }
     Ok(table)
 }
@@ -49,7 +50,8 @@ pub(crate) const KEYVAL_SEP: char = '=';
 // inline-table-keyvals-non-empty =
 // ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) /
 // ( key keyval-sep val )
-parse!(inline_table_keyvals() -> (&'a str, Vec<(InternalString, KeyValue)>), {
+
+parse!(inline_table_keyvals() -> (&'a str, Vec<(InternalString, TableKeyValue)>), {
     (
         sep_by(keyval(), char(INLINE_TABLE_SEP)),
         ws(),
@@ -58,7 +60,7 @@ parse!(inline_table_keyvals() -> (&'a str, Vec<(InternalString, KeyValue)>), {
     })
 });
 
-parse!(keyval() -> (InternalString, KeyValue), {
+parse!(keyval() -> (InternalString, TableKeyValue), {
     (
         try((ws(), key(), ws())),
         char(KEYVAL_SEP),
@@ -69,9 +71,9 @@ parse!(keyval() -> (InternalString, KeyValue), {
         let (pre, (raw, key), suf) = k;
         (
             key,
-            KeyValue {
+            TableKeyValue {
                 key: Repr::new(pre, raw, suf),
-                value: v,
+                value: Item::Value(v),
             }
         )
     })
diff --git a/src/parser/strings.rs b/src/parser/strings.rs
index 43466ecd..ec85aca5 100644
--- a/src/parser/strings.rs
+++ b/src/parser/strings.rs
@@ -96,7 +96,6 @@ parse!(basic_string() -> InternalString, {
     between(char(QUOTATION_MARK), char(QUOTATION_MARK),
             many(basic_char()))
         .message("While parsing a Basic String")
-        .map(|s: String| s.into())
 });
 
 // ;; Multiline Basic String
@@ -153,7 +152,7 @@ parse!(ml_basic_body() -> InternalString, {
                         ))
                     )
                     .skip(try_eat_escaped_newline())
-            ).map(|s: String| s.into())
+            )
         )
 });
 
@@ -214,7 +213,7 @@ parse!(ml_literal_body() -> InternalString, {
                             satisfy(is_ml_literal_char),
                         ))
                     )
-            ).map(|s: String| s.into())
+            )
         )
 });
 
diff --git a/src/parser/table.rs b/src/parser/table.rs
index d70cc927..ade5098a 100644
--- a/src/parser/table.rs
+++ b/src/parser/table.rs
@@ -9,7 +9,7 @@ use parser::key::key;
 use key::Key;
 use array_of_tables::ArrayOfTables;
 use decor::{Decor, InternalString};
-use table::{Table, TableChildMut, TableEntry};
+use table::{Item, Table};
 use std::mem;
 use std::cell::RefCell;
 // https://github.com/rust-lang/rust/issues/41358
@@ -24,9 +24,9 @@ const STD_TABLE_OPEN: char = '[';
 // std-table-close = ws %x5D     ; ] Right square bracket
 const STD_TABLE_CLOSE: char = ']';
 // array-table-open  = %x5B.5B ws  ; [[ Double left square bracket
-const ARRAY_TABLE_OPEN: &'static str = "[[";
+const ARRAY_TABLE_OPEN: &str = "[[";
 // array-table-close = ws %x5D.5D  ; ]] Double right quare bracket
-const ARRAY_TABLE_CLOSE: &'static str = "]]";
+const ARRAY_TABLE_CLOSE: &str = "]]";
 
 
 // note: this rule is not present in the original grammar
@@ -54,7 +54,7 @@ parser!{
                       parser
                       .borrow_mut()
                       .deref_mut()
-                      .on_std_header(h, t))
+                      .on_std_header(&h, t))
     }
 }
 
@@ -75,7 +75,7 @@ parser!{
                       parser
                       .borrow_mut()
                       .deref_mut()
-                      .on_array_header(h, t))
+                      .on_array_header(&h, t))
     }
 }
 
@@ -111,11 +111,15 @@ impl TomlParser {
     ) -> Result<&'a mut Table, CustomError> {
         if let Some(key) = path.get(i) {
             let mut new_table = Table::new();
-            new_table.set_implicit();
+            new_table.set_implicit(true);
 
-            match table.append_table(key, new_table) {
-                TableChildMut::Value(..) => Err(duplicate_key(path, i)),
-                TableChildMut::Array(array) => {
+            let entry = table.entry(key.raw());
+            if entry.is_none() {
+                *entry = Item::Table(new_table);
+            }
+            match *entry {
+                Item::Value(..) => Err(duplicate_key(path, i)),
+                Item::ArrayOfTables(ref mut array) => {
                     debug_assert!(!array.is_empty());
 
                     let index = array.len() - 1;
@@ -123,16 +127,17 @@ impl TomlParser {
 
                     Self::descend_path(last_child, path, i + 1)
                 }
-                TableChildMut::Table(sweet_child_of_mine) => {
+                Item::Table(ref mut sweet_child_of_mine) => {
                     TomlParser::descend_path(sweet_child_of_mine, path, i + 1)
                 }
+                _ => unreachable!(),
             }
         } else {
             Ok(table)
         }
     }
 
-    fn on_std_header(&mut self, path: Vec<Key>, trailing: &str) -> Result<(), CustomError> {
+    fn on_std_header(&mut self, path: &[Key], trailing: &str) -> Result<(), CustomError> {
         debug_assert!(!path.is_empty());
 
         let leading = mem::replace(&mut self.document.trailing, InternalString::new());
@@ -145,18 +150,19 @@ impl TomlParser {
             Ok(table) => {
                 let decor = Decor::new(leading, trailing.into());
 
-                match table.entry(key.get()) {
+                let entry = table.entry(key.raw());
+                if entry.is_none() {
+                    *entry = Item::Table(Table::with_decor(decor));
+                    self.current_table = entry.as_table_mut().unwrap();
+                    return Ok(());
+                }
+                match *entry {
                     // if [a.b.c] header preceded [a.b]
-                    TableEntry::Table(ref mut t) if t.implicit => {
-                        debug_assert!(t.key_value_pairs.is_empty());
+                    Item::Table(ref mut t) if t.implicit => {
+                        debug_assert!(t.values_len() == 0);
                         t.decor = decor;
-                        t.implicit = false;
-                        self.current_table = *t;
-                        return Ok(());
-                    }
-                    TableEntry::Vacant(ref mut parent) => {
-                        let mut table = parent.append_table(key, Table::with_decor(decor));
-                        self.current_table = table.as_table_mut().expect("table");
+                        t.set_implicit(false);
+                        self.current_table = t;
                         return Ok(());
                     }
                     _ => {}
@@ -167,7 +173,7 @@ impl TomlParser {
         }
     }
 
-    fn on_array_header(&mut self, path: Vec<Key>, trailing: &str) -> Result<(), CustomError> {
+    fn on_array_header(&mut self, path: &[Key], trailing: &str) -> Result<(), CustomError> {
         debug_assert!(!path.is_empty());
 
         let leading = mem::replace(&mut self.document.trailing, InternalString::new());
@@ -180,8 +186,10 @@ impl TomlParser {
             Ok(table) => if !table.contains_table(key.get()) && !table.contains_value(key.get()) {
                 let decor = Decor::new(leading, trailing.into());
 
-                let mut array = table.append_array(key, ArrayOfTables::new());
-                let array = array.as_array_mut().expect("array");
+                let entry = table
+                    .entry(key.raw())
+                    .or_insert(Item::ArrayOfTables(ArrayOfTables::new()));
+                let array = entry.as_array_of_tables_mut().unwrap();
                 self.current_table = array.append(Table::with_decor(decor));
 
                 Ok(())
diff --git a/src/table.rs b/src/table.rs
index 9f8221af..f32f9590 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -1,83 +1,58 @@
 use linked_hash_map::LinkedHashMap;
-use value::{sort_key_value_pairs, InlineTable, KeyValuePairs, Value};
-use decor::{Decor, InternalString};
+use value::{sort_key_value_pairs, Value};
+use decor::{Decor, InternalString, Repr};
 use key::Key;
 use array_of_tables::ArrayOfTables;
-use formatted::to_key_value;
+use formatted::{decorated, key_repr};
 
 // TODO: add method to convert a table into inline table
-// TODO: impl Index
 // TODO: documentation
 
 /// Type representing a TOML non-inline table
 #[derive(Clone, Debug, Default)]
 pub struct Table {
-    pub(crate) key_value_pairs: KeyValuePairs,
-    pub(crate) containers: LinkedHashMap<InternalString, (InternalString, Container)>,
+    pub(crate) items: KeyValuePairs,
+    // comments/spaces before and after the header
     pub(crate) decor: Decor,
+    // whether to hide an empty table
     pub(crate) implicit: bool,
 }
 
-#[derive(Clone, Debug)]
-pub(crate) enum Container {
-    Table(Table),
-    Array(ArrayOfTables),
-}
+pub(crate) type KeyValuePairs = LinkedHashMap<InternalString, TableKeyValue>;
 
-/// An immutable reference to a child
-#[derive(Clone, Debug)]
-pub enum TableChild<'a> {
-    /// A reference to a child value
-    Value(&'a Value),
-    /// A reference to a child table
-    Table(&'a Table),
-    /// A reference to a child array of tables
-    Array(&'a ArrayOfTables),
+#[derive(Debug, Clone)]
+pub enum Item {
+    None,
+    Value(Value),
+    Table(Table),
+    ArrayOfTables(ArrayOfTables),
 }
 
-pub type Iter<'a> = Box<Iterator<Item = (&'a str, TableChild<'a>)> + 'a>;
-
-/// A mutable reference to a child
-#[derive(Debug)]
-pub enum TableChildMut<'a> {
-    /// A mutable reference to a child value
-    Value(&'a mut Value),
-    /// A mutable reference to a child table
-    Table(&'a mut Table),
-    /// A mutable reference to a child array of tables
-    Array(&'a mut ArrayOfTables),
+impl Default for Item {
+    fn default() -> Self {
+        Item::None
+    }
 }
 
-pub type IterMut<'a> = Box<Iterator<Item = (&'a str, TableChildMut<'a>)> + 'a>;
-
-/// Return type of table.entry("key")
-#[derive(Debug)]
-pub enum TableEntry<'a> {
-    /// A mutable reference to a child value
-    Value(&'a mut Value),
-    /// A mutable reference to a child table
-    Table(&'a mut Table),
-    /// A mutable reference to a child array of tables
-    Array(&'a mut ArrayOfTables),
-    /// A mutable reference to the table itself
-    Vacant(&'a mut Table),
+// TODO: make pub(crate)
+#[doc(hidden)]
+#[derive(Debug, Clone)]
+pub struct TableKeyValue {
+    pub(crate) key: Repr,
+    pub(crate) value: Item,
 }
 
-impl Container {
-    fn as_table_please(&mut self) -> &mut Table {
-        match *self {
-            Container::Table(ref mut t) => t,
-            _ => unreachable!("table please"),
-        }
-    }
-    fn as_array_please(&mut self) -> &mut ArrayOfTables {
-        match *self {
-            Container::Array(ref mut a) => a,
-            _ => unreachable!("array please"),
+impl TableKeyValue {
+    pub(crate) fn new(key: Repr, value: Item) -> Self {
+        TableKeyValue {
+            key: key,
+            value: value,
         }
     }
 }
 
+pub type Iter<'a> = Box<Iterator<Item = (&'a str, &'a Item)> + 'a>;
+
 impl Table {
     pub fn new() -> Self {
         Self::with_decor(Decor::new("\n", ""))
@@ -89,159 +64,87 @@ impl Table {
             ..Default::default()
         }
     }
+
     pub fn contains_key(&self, key: &str) -> bool {
-        self.contains_value(key) || self.contains_container(key)
-    }
-    pub(crate) fn contains_value(&self, key: &str) -> bool {
-        self.key_value_pairs.contains_key(key)
-    }
-    fn contains_container(&self, key: &str) -> bool {
-        self.containers.contains_key(key)
-    }
-    pub(crate) fn contains_table(&self, key: &str) -> bool {
-        match self.containers.get(key) {
-            Some(&(_, Container::Table(..))) => true,
-            _ => false,
+        if let Some(kv) = self.items.get(key) {
+            !kv.value.is_none()
+        } else {
+            false
         }
     }
-    /// Iterator over key/value pairs, arrays of tables and subtables.
-    pub fn iter(&self) -> Iter {
-        Box::new(
-            self.key_value_pairs
-                .iter()
-                .map(|(k, kv)| (&k[..], TableChild::Value(&kv.value)))
-                .chain(self.containers.iter().map(|(k, c)| {
-                    (
-                        &k[..],
-                        match c.1 {
-                            Container::Table(ref t) => TableChild::Table(t),
-                            Container::Array(ref a) => TableChild::Array(a),
-                        },
-                    )
-                })),
-        )
-    }
-
 
-    /// Mutable iterator over key/value pairs, arrays of tables and subtables.
-    pub fn iter_mut(&mut self) -> IterMut {
-        Box::new(
-            self.key_value_pairs
-                .iter_mut()
-                .map(|(k, kv)| (&k[..], TableChildMut::Value(&mut kv.value)))
-                .chain(self.containers.iter_mut().map(|(k, p)| {
-                    (
-                        &k[..],
-                        match p.1 {
-                            Container::Table(ref mut t) => TableChildMut::Table(t),
-                            Container::Array(ref mut a) => TableChildMut::Array(a),
-                        },
-                    )
-                })),
-        )
+    pub fn contains_table(&self, key: &str) -> bool {
+        if let Some(kv) = self.items.get(key) {
+            kv.value.is_table()
+        } else {
+            false
+        }
     }
 
-    /// Moves all elements from `other` into `Self`, leaving `other` empty.
-    ///
-    /// **Note**: this method will remove comments from overwritten key/value pairs.
-    pub fn append(&mut self, other: &mut InlineTable) {
-        while let Some((k, kv)) = other.key_value_pairs.pop_front() {
-            self.key_value_pairs.insert(k, kv);
+    pub fn contains_value(&self, key: &str) -> bool {
+        if let Some(kv) = self.items.get(key) {
+            kv.value.is_value()
+        } else {
+            false
         }
     }
 
-    pub fn remove(&mut self, key: &str) -> bool {
-        self.remove_container(key) || self.remove_value(key).is_some()
+    pub fn contains_array_of_tables(&self, key: &str) -> bool {
+        if let Some(kv) = self.items.get(key) {
+            kv.value.is_array_of_tables()
+        } else {
+            false
+        }
     }
 
-    pub fn remove_value(&mut self, key: &str) -> Option<Value> {
-        let val = self.key_value_pairs.remove(key).map(|kv| kv.value);
-        if val.is_some() {
-            self.set_implicit();
-        }
-        val
+    pub fn iter(&self) -> Iter {
+        Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value)))
     }
 
-    fn remove_container(&mut self, key: &str) -> bool {
-        self.containers.remove(key).is_some()
+    pub fn remove(&mut self, key: &str) -> Option<Item> {
+        self.items.remove(key).map(|kv| kv.value)
     }
 
     /// Sorts Key/Value Pairs of the table,
     /// doesn't affect subtables or subarrays.
     pub fn sort_values(&mut self) {
-        sort_key_value_pairs(&mut self.key_value_pairs);
+        sort_key_value_pairs(&mut self.items);
     }
 
+    /// Returns the number of non-empty items in the table.
     pub fn len(&self) -> usize {
-        self.key_value_pairs.len() + self.containers.len()
+        self.items.iter().filter(|i| !(i.1).value.is_none()).count()
     }
 
-    pub fn is_empty(&self) -> bool {
-        self.len() == 0
+    /// Returns the number of key/value pairs in the table.
+    pub fn values_len(&self) -> usize {
+        self.items.iter().filter(|i| (i.1).value.is_value()).count()
     }
 
-    pub fn get<'a>(&'a self, key: &str) -> Option<TableChild<'a>> {
-        if let Some(c) = self.containers.get(key) {
-            match c.1 {
-                Container::Table(ref t) => Some(TableChild::Table(t)),
-                Container::Array(ref a) => Some(TableChild::Array(a)),
-            }
-        } else if let Some(kv) = self.key_value_pairs.get(key) {
-            Some(TableChild::Value(&kv.value))
-        } else {
-            None
-        }
-    }
-
-    pub fn entry<'a>(&'a mut self, key: &str) -> TableEntry<'a> {
-        if !self.contains_key(key) {
-            TableEntry::Vacant(self)
-        } else if let Some(c) = self.containers.get_mut(key) {
-            match c.1 {
-                Container::Table(ref mut t) => TableEntry::Table(t),
-                Container::Array(ref mut a) => TableEntry::Array(a),
-            }
-        } else {
-            let kv = self.key_value_pairs
-                .get_mut(key)
-                .expect("non-lexical lifetimes");
-            TableEntry::Value(&mut kv.value)
-        }
-    }
-
-    pub fn append_value<V: Into<Value>>(&mut self, key: &Key, value: V) -> TableChildMut {
-        match self.entry(key.get()) {
-            TableEntry::Vacant(me) => {
-                TableChildMut::Value(me.append_value_assume_vacant(key, value.into()))
-            }
-            TableEntry::Array(v) => TableChildMut::Array(v),
-            TableEntry::Table(v) => TableChildMut::Table(v),
-            TableEntry::Value(v) => TableChildMut::Value(v),
-        }
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
     }
 
-    pub fn append_table(&mut self, key: &Key, table: Table) -> TableChildMut {
-        match self.entry(key.get()) {
-            TableEntry::Vacant(me) => {
-                TableChildMut::Table(me.append_table_assume_vacant(key, table))
-            }
-            TableEntry::Array(v) => TableChildMut::Array(v),
-            TableEntry::Table(v) => TableChildMut::Table(v),
-            TableEntry::Value(v) => TableChildMut::Value(v),
-        }
+    /// Given the `key`, return a mutable reference to the value.
+    /// If there is no entry associated with the given key in the table,
+    /// a `Item::None` value will be inserted.
+    ///
+    /// To insert to item, use `entry` to return a mutable reference
+    /// and set it to the appropriate value.
+    pub fn entry<'a>(&'a mut self, key: &str) -> &'a mut Item {
+        let parsed_key = key.parse::<Key>().expect("invalid key");
+        &mut self.items
+            .entry(parsed_key.get().to_owned())
+            .or_insert(TableKeyValue::new(key_repr(parsed_key.raw()), Item::None))
+            .value
     }
 
-    pub fn append_array(&mut self, key: &Key, array: ArrayOfTables) -> TableChildMut {
-        match self.entry(key.get()) {
-            TableEntry::Vacant(me) => {
-                TableChildMut::Array(me.append_array_assume_vacant(key, array))
-            }
-            TableEntry::Array(v) => TableChildMut::Array(v),
-            TableEntry::Table(v) => TableChildMut::Table(v),
-            TableEntry::Value(v) => TableChildMut::Value(v),
-        }
+    pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> {
+        self.items.get(key).map(|kv| &kv.value)
     }
 
+    /// If a table has no key value pairs and implicit, it will not be displayed.
+    ///
     /// # Examples
     ///
     /// ```notrust
@@ -257,241 +160,87 @@ impl Table {
     /// # fn main() {
     /// let mut doc = "[a]\n[a.b]\n".parse::<Document>().expect("valid toml");
     ///
-    /// assert!(doc.root.entry("a").as_table_mut().unwrap().set_implicit());
+    /// doc.root.entry("a").as_table_mut().unwrap().set_implicit(true);
     /// assert_eq!(doc.to_string(), "[a.b]\n");
     /// # }
     /// ```
-    pub fn set_implicit(&mut self) -> bool {
-        if self.key_value_pairs.is_empty() && !self.implicit {
-            self.implicit = true;
-            true
-        } else {
-            false
-        }
+    pub fn set_implicit(&mut self, implicit: bool) {
+        self.implicit = implicit;
     }
+}
 
-    fn append_value_assume_vacant(&mut self, key: &Key, value: Value) -> &mut Value {
-        debug_assert!(!self.contains_key(key.get()));
-        let kv = to_key_value(key.raw(), value);
-        if self.implicit {
-            self.implicit = false;
+impl Item {
+    pub fn or_insert(&mut self, item: Item) -> &mut Item {
+        if self.is_none() {
+            *self = item
         }
-        &mut self.key_value_pairs
-            .entry(key.get().into())
-            .or_insert(kv)
-            .value
-    }
-
-    pub(crate) fn append_array_assume_vacant(
-        &mut self,
-        key: &Key,
-        array: ArrayOfTables,
-    ) -> &mut ArrayOfTables {
-        debug_assert!(!self.contains_key(key.get()));
-        let pair = (key.raw().into(), Container::Array(array));
-        let result = self.containers
-            .entry(key.get().into())
-            .or_insert_with(|| pair);
-        result.1.as_array_please()
-    }
-
-    pub(crate) fn append_table_assume_vacant(&mut self, key: &Key, table: Table) -> &mut Table {
-        debug_assert!(!self.contains_key(key.get()));
-        let pair = (key.raw().to_owned(), Container::Table(table));
-        let result = self.containers
-            .entry(key.get().into())
-            .or_insert_with(|| pair);
-        result.1.as_table_please()
+        self
     }
 }
-
 // TODO: This should be generated by macro or derive
 /// Downcasting
-impl<'a> TableEntry<'a> {
-    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
-        match *self {
-            TableEntry::Table(ref mut me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_array_mut(&mut self) -> Option<&mut ArrayOfTables> {
-        match *self {
-            TableEntry::Array(ref mut me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_value_mut(&mut self) -> Option<&mut Value> {
+impl Item {
+    pub fn as_value(&self) -> Option<&Value> {
         match *self {
-            TableEntry::Value(ref mut me) => Some(me),
+            Item::Value(ref v) => Some(v),
             _ => None,
         }
     }
-    pub fn as_vacant_mut(&mut self) -> Option<&mut Table> {
+    pub fn as_table(&self) -> Option<&Table> {
         match *self {
-            TableEntry::Vacant(ref mut me) => Some(me),
+            Item::Table(ref t) => Some(t),
             _ => None,
         }
     }
-    pub fn as_table(&self) -> Option<&Table> {
+    pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> {
         match *self {
-            TableEntry::Table(ref me) => Some(me),
+            Item::ArrayOfTables(ref a) => Some(a),
             _ => None,
         }
     }
-    pub fn as_array(&self) -> Option<&ArrayOfTables> {
+    pub fn as_value_mut(&mut self) -> Option<&mut Value> {
         match *self {
-            TableEntry::Array(ref me) => Some(me),
+            Item::Value(ref mut v) => Some(v),
             _ => None,
         }
     }
-    pub fn as_value(&self) -> Option<&Value> {
+    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
         match *self {
-            TableEntry::Value(ref me) => Some(me),
+            Item::Table(ref mut t) => Some(t),
             _ => None,
         }
     }
-    pub fn as_vacant(&self) -> Option<&Table> {
+    pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> {
         match *self {
-            TableEntry::Vacant(ref me) => Some(me),
+            Item::ArrayOfTables(ref mut a) => Some(a),
             _ => None,
         }
     }
-    pub fn is_table(&self) -> bool {
-        self.as_table().is_some()
-    }
-    pub fn is_array(&self) -> bool {
-        self.as_array().is_some()
-    }
     pub fn is_value(&self) -> bool {
         self.as_value().is_some()
     }
-    pub fn is_vacant(&self) -> bool {
-        self.as_vacant().is_some()
-    }
-}
-
-/// Downcasting
-impl<'a> TableChild<'a> {
-    pub fn as_table(&self) -> Option<&'a Table> {
-        match *self {
-            TableChild::Table(me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_array(&self) -> Option<&'a ArrayOfTables> {
-        match *self {
-            TableChild::Array(me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_value(&self) -> Option<&'a Value> {
-        match *self {
-            TableChild::Value(me) => Some(me),
-            _ => None,
-        }
-    }
     pub fn is_table(&self) -> bool {
         self.as_table().is_some()
     }
-    pub fn is_array(&self) -> bool {
-        self.as_array().is_some()
+    pub fn is_array_of_tables(&self) -> bool {
+        self.as_array_of_tables().is_some()
     }
-    pub fn is_value(&self) -> bool {
-        self.as_value().is_some()
-    }
-
-    pub fn get(&self, key: &str) -> Option<TableChild<'a>> {
+    pub fn is_none(&self) -> bool {
         match *self {
-            TableChild::Value(v) if v.is_inline_table() => {
-                let t = v.as_inline_table().unwrap();
-                t.get(key).map(|v| TableChild::Value(v))
-            }
-            TableChild::Table(t) => t.get(key),
-            _ => None,
+            Item::None => true,
+            _ => false,
         }
     }
 }
 
-/// Downcasting
-impl<'a> TableChildMut<'a> {
-    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
-        match *self {
-            TableChildMut::Table(ref mut me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_array_mut(&mut self) -> Option<&mut ArrayOfTables> {
-        match *self {
-            TableChildMut::Array(ref mut me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_value_mut(&mut self) -> Option<&mut Value> {
-        match *self {
-            TableChildMut::Value(ref mut me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_table(&self) -> Option<&Table> {
-        match *self {
-            TableChildMut::Table(ref me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_array(&self) -> Option<&ArrayOfTables> {
-        match *self {
-            TableChildMut::Array(ref me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn as_value(&self) -> Option<&Value> {
-        match *self {
-            TableChildMut::Value(ref me) => Some(me),
-            _ => None,
-        }
-    }
-    pub fn is_table(&self) -> bool {
-        self.as_table().is_some()
-    }
-    pub fn is_array(&self) -> bool {
-        self.as_array().is_some()
-    }
-    pub fn is_value(&self) -> bool {
-        self.as_value().is_some()
-    }
+pub fn value<V: Into<Value>>(v: V) -> Item {
+    Item::Value(decorated(v.into(), " ", ""))
 }
 
-impl<'a> TableChildMut<'a> {
-    pub fn into_entry(self) -> TableEntry<'a> {
-        match self {
-            TableChildMut::Table(t) => TableEntry::Table(t),
-            TableChildMut::Array(t) => TableEntry::Array(t),
-            TableChildMut::Value(t) => TableEntry::Value(t),
-        }
-    }
+pub fn table() -> Item {
+    Item::Table(Table::new())
 }
 
-impl<'e> TableEntry<'e> {
-    pub fn get(self, s: &str) -> TableEntry<'e> {
-        match self {
-            TableEntry::Table(table) => table.entry(s),
-            TableEntry::Value(&mut Value::InlineTable(ref mut t)) if t.contains_key(s) => {
-                t.get_mut(s).map(TableEntry::Value).unwrap()
-            }
-            a => a,
-        }
-    }
-
-    pub fn get_or_insert(self, s: &str) -> TableEntry<'e> {
-        let key: Key = s.parse().expect("valid key");
-        match self {
-            TableEntry::Value(&mut Value::InlineTable(ref mut t)) => TableEntry::Value(
-                t.try_insert(&key, Value::InlineTable(InlineTable::default())),
-            ),
-            TableEntry::Vacant(table) | TableEntry::Table(table) => {
-                table.append_table(&key, Table::new()).into_entry()
-            }
-            _ => panic!("can't access key {} in {:?}", s, self),
-        }
-    }
+pub fn array() -> Item {
+    Item::ArrayOfTables(ArrayOfTables::new())
 }
diff --git a/src/value.rs b/src/value.rs
index 810ac156..24768bb3 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -1,10 +1,11 @@
 use std::str::FromStr;
+use std::mem;
 use chrono::{self, FixedOffset};
 use formatted;
 use linked_hash_map::LinkedHashMap;
-use std::slice::Iter;
-use decor::{Decor, Formatted, InternalString, Repr};
+use decor::{Decor, Formatted, InternalString};
 use key::Key;
+use table::{Item, KeyValuePairs, TableKeyValue};
 use parser;
 use combine;
 use combine::Parser;
@@ -36,7 +37,8 @@ pub enum DateTime {
 /// payload of the `Value::Array` variant's value
 #[derive(Debug, Default, Clone)]
 pub struct Array {
-    pub(crate) values: Vec<Value>,
+    // always Vec<Item::Value>
+    pub(crate) values: Vec<Item>,
     // `trailing` represents whitespaces, newlines
     // and comments in an empty array or after the trailing comma
     pub(crate) trailing: InternalString,
@@ -49,22 +51,13 @@ pub struct Array {
 /// payload of the `Value::InlineTable` variant
 #[derive(Debug, Default, Clone)]
 pub struct InlineTable {
-    pub(crate) key_value_pairs: KeyValuePairs,
+    pub(crate) items: KeyValuePairs,
     // `preamble` represents whitespaces in an empty table
     pub(crate) preamble: InternalString,
     // prefix before `{` and suffix after `}`
     pub(crate) decor: Decor,
 }
 
-pub(crate) type KeyValuePairs = LinkedHashMap<InternalString, KeyValue>;
-
-/// Type representing a TOML Key/Value Pair
-#[derive(Debug, Clone)]
-pub struct KeyValue {
-    pub(crate) key: Repr,
-    pub(crate) value: Value,
-}
-
 #[derive(Eq, PartialEq, Clone, Copy, Debug, Hash)]
 pub(crate) enum ValueType {
     None,
@@ -77,6 +70,7 @@ pub(crate) enum ValueType {
     InlineTable,
 }
 
+pub type ArrayIter<'a> = Box<Iterator<Item = &'a Value> + 'a>;
 
 impl Array {
     pub fn len(&self) -> usize {
@@ -87,8 +81,8 @@ impl Array {
         self.len() == 0
     }
 
-    pub fn iter(&self) -> Iter<Value> {
-        self.values.iter()
+    pub fn iter(&self) -> ArrayIter {
+        Box::new(self.values.iter().filter_map(|i| i.as_value()))
     }
 
     pub fn push<V: Into<Value>>(&mut self, v: V) -> bool {
@@ -96,7 +90,7 @@ impl Array {
     }
 
     pub fn get(&mut self, index: usize) -> Option<&Value> {
-        self.values.get(index)
+        self.values.get(index).and_then(Item::as_value)
     }
 
     pub fn remove(&mut self, index: usize) -> Value {
@@ -104,7 +98,10 @@ impl Array {
         if self.is_empty() {
             self.trailing_comma = false;
         }
-        removed
+        match removed {
+            Item::Value(v) => v,
+            x => panic!("non-value item {:?} in an array", x),
+        }
     }
 
     /// Auto formats the array
@@ -113,14 +110,14 @@ impl Array {
     }
 
     pub(crate) fn push_value(&mut self, v: Value, decorate: bool) -> bool {
-        let mut value = v.into();
+        let mut value = v;
         if !self.is_empty() && decorate {
             formatted::decorate(&mut value, " ", "");
         } else if decorate {
             formatted::decorate(&mut value, "", "");
         }
         if self.is_empty() || value.get_type() == self.value_type() {
-            self.values.push(value);
+            self.values.push(Item::Value(value));
             true
         } else {
             false
@@ -128,7 +125,7 @@ impl Array {
     }
 
     pub(crate) fn value_type(&self) -> ValueType {
-        if let Some(value) = self.values.get(0) {
+        if let Some(value) = self.values.get(0).and_then(Item::as_value) {
             value.get_type()
         } else {
             ValueType::None
@@ -136,50 +133,53 @@ impl Array {
     }
 }
 
+pub type InlineTableIter<'a> = Box<Iterator<Item = (&'a str, &'a Value)> + 'a>;
+
 impl InlineTable {
     pub fn len(&self) -> usize {
-        self.key_value_pairs.len()
+        self.items.len()
     }
 
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
-    pub fn iter<'a>(&'a self) -> Box<Iterator<Item = (&'a str, &'a Value)> + 'a> {
+    pub fn iter(&self) -> InlineTableIter {
         Box::new(
-            self.key_value_pairs
+            self.items
                 .iter()
-                .map(|(k, kv)| (&k[..], &kv.value)),
+                .filter(|&(_, kv)| kv.value.is_value())
+                .map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())),
         )
     }
 
     pub fn sort(&mut self) {
-        sort_key_value_pairs(&mut self.key_value_pairs);
+        sort_key_value_pairs(&mut self.items);
     }
 
     pub fn contains_key(&self, key: &str) -> bool {
-        self.key_value_pairs.contains_key(key)
-    }
-
-    pub fn try_insert<V: Into<Value>>(&mut self, key: &Key, value: V) -> &mut Value {
-        let kv = formatted::to_key_value(key.raw(), value.into());
-        &mut self.key_value_pairs
-            .entry(key.get().into())
-            .or_insert(kv)
-            .value
+        if let Some(kv) = self.items.get(key) {
+            !kv.value.is_none()
+        } else {
+            false
+        }
     }
 
-    pub fn insert<V: Into<Value>>(&mut self, key: &Key, value: V) -> Option<Value> {
-        let kv = formatted::to_key_value(key.raw(), value.into());
-        self.key_value_pairs
-            .insert(key.get().into(), kv)
-            .map(|p| p.value)
+    pub fn merge_into(&mut self, other: &mut InlineTable) {
+        let items = mem::replace(&mut self.items, KeyValuePairs::new());
+        for (k, kv) in items {
+            other.items.insert(k, kv);
+        }
     }
 
-    pub fn append(&mut self, other: &mut InlineTable) {
-        while let Some((k, kv)) = other.key_value_pairs.pop_front() {
-            self.key_value_pairs.insert(k, kv);
-        }
+    pub fn get_or_insert<V: Into<Value>>(&mut self, key: &str, value: V) -> &mut Value {
+        let parsed = key.parse::<Key>().expect("invalid key");
+        self.items
+            .entry(parsed.get().to_owned())
+            .or_insert(formatted::to_key_value(key, value.into()))
+            .value
+            .as_value_mut()
+            .expect("non-value type in inline table")
     }
 
     /// Auto formats the table
@@ -188,15 +188,19 @@ impl InlineTable {
     }
 
     pub fn remove(&mut self, key: &str) -> Option<Value> {
-        self.key_value_pairs.remove(key).map(|kv| kv.value)
+        self.items
+            .remove(key)
+            .and_then(|kv| kv.value.as_value().cloned())
     }
 
     pub fn get(&self, key: &str) -> Option<&Value> {
-        self.key_value_pairs.get(key).map(|kv| &kv.value)
+        self.items.get(key).and_then(|kv| kv.value.as_value())
     }
 
     pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
-        self.key_value_pairs.get_mut(key).map(|kv| &mut kv.value)
+        self.items
+            .get_mut(key)
+            .and_then(|kv| kv.value.as_value_mut())
     }
 }
 
@@ -346,11 +350,15 @@ impl Value {
     }
 }
 
-pub(crate) fn sort_key_value_pairs(pairs: &mut KeyValuePairs) {
-    let mut keys: Vec<InternalString> = pairs.keys().cloned().collect();
+pub(crate) fn sort_key_value_pairs(items: &mut LinkedHashMap<InternalString, TableKeyValue>) {
+    let mut keys: Vec<InternalString> = items
+        .iter()
+        .filter_map(|i| (i.1).value.as_value().map(|_| i.0))
+        .cloned()
+        .collect();
     keys.sort();
     for key in keys {
-        pairs.get_refresh(&key);
+        items.get_refresh(&key);
     }
 }
 


Test patch:
diff --git a/tests/test_edit.rs b/tests/test_edit.rs
index 286196b9..4256bddf 100644
--- a/tests/test_edit.rs
+++ b/tests/test_edit.rs
@@ -23,7 +23,7 @@ macro_rules! as_table {
 #[cfg(test)]
 #[cfg_attr(rustfmt, rustfmt_skip)]
 mod tests {
-    use toml_edit::{Document, Key, Value, Table, ArrayOfTables};
+    use toml_edit::{Document, Key, Value, Table, value, table, array};
     use std::iter::FromIterator;
 
     struct Test {
@@ -67,12 +67,9 @@ fn test_insert_leaf_table() {
 
         [other.table]"#
     ).running(|root| {
-        let mut servers = root.entry("servers");
-        let servers = as_table!(servers);
-        let mut beta = servers.append_table(parse_key!("beta"), Table::new());
-        let beta = as_table!(beta);
-        beta.append_value(parse_key!("ip"), "10.0.0.2");
-        beta.append_value(parse_key!("dc"), "eqdc10");
+        root["servers"]["beta"] = table();
+        root["servers"]["beta"]["ip"] = value("10.0.0.2");
+        root["servers"]["beta"]["dc"] = value("eqdc10");
     }).produces(r#"
         [servers]
 
@@ -94,12 +91,10 @@ fn test_insert_nonleaf_table() {
     given(r#"
         [other.table]"#
     ).running(|root| {
-        let mut servers = root.append_table(parse_key!("servers"), Table::new());
-        let servers = as_table!(servers);
-        let mut alpha = servers.append_table(parse_key!("alpha"), Table::new());
-        let alpha = as_table!(alpha);
-        alpha.append_value(parse_key!("ip"), "10.0.0.1");
-        alpha.append_value(parse_key!("dc"), "eqdc10");
+        root["servers"] = table();
+        root["servers"]["alpha"] = table();
+        root["servers"]["alpha"]["ip"] = value("10.0.0.1");
+        root["servers"]["alpha"]["dc"] = value("eqdc10");
     }).produces(r#"
         [other.table]
 
@@ -118,12 +113,12 @@ fn test_insert_array() {
         [package]
         title = "withoutarray""#
     ).running(|root| {
-        let mut array = root.append_array(parse_key!("bin"), ArrayOfTables::new());
-        assert!(array.is_array());
-        let array = array.as_array_mut().unwrap();
+        root["bin"] = array();
+        assert!(root["bin"].is_array_of_tables());
+        let array = root["bin"].as_array_of_tables_mut().unwrap();
         {
-            let mut first = array.append(Table::new());
-            first.append_value(parse_key!("hello"), "world");
+            let first = array.append(Table::new());
+            first["hello"] = value("world");
         }
         array.append(Table::new());
     }).produces(r#"
@@ -144,11 +139,9 @@ fn test_insert_values() {
     given(r#"
         [tbl.son]"#
     ).running(|root| {
-        let mut table = root.entry("tbl");
-        let table = as_table!(table);
-        table.append_value(parse_key!("key1"), "value1");
-        table.append_value(parse_key!("\"key2\""), 42);
-        table.append_value(parse_key!("'key3'"), 8.1415926);
+        root["tbl"]["key1"] = value("value1");
+        root["tbl"]["\"key2\""] = value(42);
+        root["tbl"]["'key3'"] = value(8.1415926);
     }).produces(r#"
 [tbl]
 key1 = "value1"
@@ -176,9 +169,9 @@ fn test_remove_leaf_table() {
         ip = "10.0.0.2"
         dc = "eqdc10""#
     ).running(|root| {
-        let mut servers = root.entry("servers");
+        let servers = root.entry("servers");
         let servers = as_table!(servers);
-        assert!(servers.remove("alpha"));
+        assert!(servers.remove("alpha").is_some());
     }).produces(r#"
         [servers]
 
@@ -225,7 +218,7 @@ fn test_remove_nonleaf_table() {
 
 
     "#).running(|root| {
-        assert!(root.remove("a"));
+        assert!(root.remove("a").is_some());
     }).produces(r#"
         title = "not relevant"
         # comment 2
@@ -257,11 +250,12 @@ fn test_remove_array_entry() {
         name = "delete me please"
         path = "src/bin/dmp/main.rs""#
     ).running(|root| {
-        let mut dmp = root.entry("bin");
-        assert!(dmp.is_array());
-        let dmp = dmp.as_array_mut().unwrap();
+        let dmp = root.entry("bin");
+        assert!(dmp.is_array_of_tables());
+        let dmp = dmp.as_array_of_tables_mut().unwrap();
         assert_eq!(dmp.len(), 2);
         dmp.remove(1);
+        assert_eq!(dmp.len(), 1);
     }).produces(r#"
         [package]
         name = "hello"
@@ -295,7 +289,7 @@ fn test_remove_array() {
         name = "delete me please"
         path = "src/bin/dmp/main.rs""#
     ).running(|root| {
-        assert!(root.remove("bin"));
+        assert!(root.remove("bin").is_some());
     }).produces(r#"
         [package]
         name = "hello"
@@ -316,9 +310,11 @@ fn test_remove_value() {
         version = "1.0.0" # please
         documentation = "https://docs.rs/hello""#
     ).running(|root| {
-        let value = root.remove_value("version");
+        let value = root.remove("version");
         assert!(value.is_some());
         let value = value.unwrap();
+        assert!(value.is_value());
+        let value = value.as_value().unwrap();
         assert!(value.is_str());
         let value = value.as_str().unwrap();
         assert_eq!(value, "1.0.0");
@@ -330,17 +326,20 @@ fn test_remove_value() {
 }
 
 #[test]
-fn test_remove_last_value() {
+fn test_remove_last_value_from_implicit() {
     given(r#"
         [a]
         b = 1"#
     ).running(|root| {
-        let mut a = root.entry("a");
+        let a = root.entry("a");
         assert!(a.is_table());
         let a = as_table!(a);
-        let value = a.remove_value("b");
+        a.set_implicit(true);
+        let value = a.remove("b");
         assert!(value.is_some());
         let value = value.unwrap();
+        assert!(value.is_value());
+        let value = value.as_value().unwrap();
         assert_eq!(value.as_integer(), Some(1));
     }).produces(r#""#);
 }
@@ -360,7 +359,7 @@ fn test_sort_values() {
 
         [a.y]"#
     ).running(|root| {
-        let mut a = root.entry("a");
+        let a = root.entry("a");
         let a = as_table!(a);
         a.sort_values();
     }).produces(r#"
@@ -381,7 +380,7 @@ macro_rules! as_array {
     ($entry:ident) => (
         {
             assert!($entry.is_value());
-            let mut a = $entry.as_value_mut().unwrap();
+            let a = $entry.as_value_mut().unwrap();
             assert!(a.is_array());
             a.as_array_mut().unwrap()
         }
@@ -395,16 +394,16 @@ fn test_insert_into_array() {
         b = []"#
     ).running(|root| {
         {
-            let mut a = root.entry("a");
-            let mut a = as_array!(a);
+            let a = root.entry("a");
+            let a = as_array!(a);
             assert_eq!(a.len(), 3);
             assert!(a.get(2).is_some());
             assert!(a.push(4));
             assert_eq!(a.len(), 4);
             a.fmt();
         }
-        let mut b = root.entry("b");
-        let mut b = as_array!(b);
+        let b = root.entry("b");
+        let b = as_array!(b);
         assert!(b.is_empty());
         assert!(b.push("hello"));
         assert_eq!(b.len(), 1);
@@ -422,14 +421,14 @@ fn test_remove_from_array() {
         b = ["hello"]"#
     ).running(|root| {
         {
-            let mut a = root.entry("a");
-            let mut a = as_array!(a);
+            let a = root.entry("a");
+            let a = as_array!(a);
             assert_eq!(a.len(), 4);
             assert!(a.remove(3).is_integer());
             assert_eq!(a.len(), 3);
         }
-        let mut b = root.entry("b");
-        let mut b = as_array!(b);
+        let b = root.entry("b");
+        let b = as_array!(b);
         assert_eq!(b.len(), 1);
         assert!(b.remove(0).is_str());
         assert!(b.is_empty());
@@ -444,7 +443,7 @@ macro_rules! as_inline_table {
     ($entry:ident) => (
         {
             assert!($entry.is_value());
-            let mut a = $entry.as_value_mut().unwrap();
+            let a = $entry.as_value_mut().unwrap();
             assert!(a.is_inline_table());
             a.as_inline_table_mut().unwrap()
         }
@@ -458,18 +457,18 @@ fn test_insert_into_inline_table() {
         b = {}"#
     ).running(|root| {
         {
-            let mut a = root.entry("a");
-            let mut a = as_inline_table!(a);
+            let a = root.entry("a");
+            let a = as_inline_table!(a);
             assert_eq!(a.len(), 2);
             assert!(a.contains_key("a") && a.get("c").is_some());
-            assert!(a.insert(parse_key!("b"), 42).is_none());
+            a.get_or_insert("b", 42);
             assert_eq!(a.len(), 3);
             a.fmt();
         }
-        let mut b = root.entry("b");
-        let mut b = as_inline_table!(b);
+        let b = root.entry("b");
+        let b = as_inline_table!(b);
         assert!(b.is_empty());
-        assert!(b.insert(parse_key!("'hello'"), "world").is_none());
+        b.get_or_insert("'hello'", "world");
         assert_eq!(b.len(), 1);
         b.fmt()
     }).produces(r#"
@@ -486,14 +485,14 @@ fn test_remove_from_inline_table() {
         b = {'hello' = "world"}"#
     ).running(|root| {
         {
-            let mut a = root.entry("a");
-            let mut a = as_inline_table!(a);
+            let a = root.entry("a");
+            let a = as_inline_table!(a);
             assert_eq!(a.len(), 3);
             assert!(a.remove("c").is_some());
             assert_eq!(a.len(), 2);
         }
-        let mut b = root.entry("b");
-        let mut b = as_inline_table!(b);
+        let b = root.entry("b");
+        let b = as_inline_table!(b);
         assert_eq!(b.len(), 1);
         assert!(b.remove("hello").is_some());
         assert!(b.is_empty());
@@ -520,7 +519,7 @@ fn test_inline_table_append() {
     ]);
     let b = b.as_inline_table_mut().unwrap();
 
-    a.append(b);
+    b.merge_into(a);
     assert_eq!(a.len(), 5);
     assert!(a.contains_key("e"));
     assert!(b.is_empty());
diff --git a/tests/test_valid.rs b/tests/test_valid.rs
index 340ab4dc..3d18cd43 100644
--- a/tests/test_valid.rs
+++ b/tests/test_valid.rs
@@ -4,9 +4,9 @@ extern crate toml_edit;
 use serde_json::Value as Json;
 use serde_json::Map as JsonMap;
 
-use toml_edit::{Document, TableChild, Value};
+use toml_edit::{Document, Item, Value, Iter};
 
-fn pair_to_json((key, value): (&str, TableChild)) -> (String, Json) {
+fn pair_to_json((key, value): (&str, Item)) -> (String, Json) {
     fn typed_json(s: &str, json: Json) -> Json {
         let mut map = JsonMap::new();
         map.insert("type".to_owned(), Json::String(s.into()));
@@ -25,21 +25,30 @@ fn pair_to_json((key, value): (&str, TableChild)) -> (String, Json) {
                 typed_json("array", json)
             }
             Value::InlineTable(ref t) => {
-                to_json(Box::new(t.iter().map(|(k, v)| (k, TableChild::Value(v)))))
+                to_json(Box::new(t.iter().map(|(k, v)| (k, Item::Value(v.clone())))))
             }
         }
     }
     let json = match value {
-        TableChild::Value(v) => value_to_json(v),
-        TableChild::Array(arr) => {
-            Json::Array(arr.iter().map(|t| to_json(t.iter())).collect::<Vec<_>>())
+        Item::Value(ref v) => value_to_json(v),
+        Item::ArrayOfTables(ref arr) => {
+            Json::Array(arr.iter().map(|t| to_json(iter_to_owned(t.iter()))).collect::<Vec<_>>())
         }
-        TableChild::Table(table) => to_json(table.iter()),
+        Item::Table(ref table) => to_json(iter_to_owned(table.iter())),
+        Item::None => Json::Null,
     };
     (key.to_owned(), json)
 }
 
-fn to_json<'a>(iter: Box<Iterator<Item = (&'a str, TableChild<'a>)> + 'a>) -> Json {
+fn iter_to_owned(iter: Iter) -> OwnedIter {
+    Box::new(
+        iter.map(|(k, v)| (k, v.clone()))
+    )
+}
+
+type OwnedIter<'s> = Box<Iterator<Item = (&'s str, Item)> + 's>;
+
+fn to_json(iter: OwnedIter) -> Json {
     Json::Object(iter.map(pair_to_json).collect())
 }
 
@@ -49,7 +58,7 @@ fn run(json: &str, toml: &str) {
     let doc = doc.unwrap();
 
     let json: Json = serde_json::from_str(json).unwrap();
-    let toml_json = to_json(doc.iter());
+    let toml_json = to_json(iter_to_owned(doc.iter()));
     // compare structure with jsons
     assert_eq!(json, toml_json);
 
@@ -71,6 +80,34 @@ macro_rules! t(
     )
 );
 
+#[test]
+fn table_reordering() {
+    let toml = r#"
+[[bin]] # bin 1
+[a.b.c.e]
+[a]
+[other.table]
+[[bin]] # bin 2
+[a.b.c.d]
+[a.b.c]
+[[bin]] # bin 3
+"#;
+    let expected = r#"
+[[bin]] # bin 1
+[[bin]] # bin 2
+[[bin]] # bin 3
+[a]
+[a.b.c]
+[a.b.c.e]
+[a.b.c.d]
+[other.table]
+"#;
+    let doc = toml.parse::<Document>();
+    assert!(doc.is_ok());
+    let doc = doc.unwrap();
+    assert_eq!(doc.to_string(), expected);
+}
+
 t!(
     test_array_empty,
     "fixtures/valid/array-empty.json",