Repository: toml-rs/toml
Pull request #457 (2023-01-18 03:41:12)

feat(toml)!: Update parser by using `toml_edit`
`toml_edit::de::Deserializer` got a `FromStr` so callers could bypass the `despan` calls for extra performance.

This is a step towards #340 

Tried to capture regressions in errors in
- #450
- #451 
- #452 
- #453 
- #454 
- #455 
- #456

BREAKING CHANGES:
- `Deserializer` now only handles documents, use `ValueDeserializer` otherwise
- `from_slice` removed


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 5e212963..de16d1a1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -897,6 +897,7 @@ dependencies = [
  "snapbox",
  "toml-test-harness",
  "toml_datetime",
+ "toml_edit",
 ]
 
 [[package]]
diff --git a/crates/toml/Cargo.toml b/crates/toml/Cargo.toml
index 267b2d51..22a353a8 100644
--- a/crates/toml/Cargo.toml
+++ b/crates/toml/Cargo.toml
@@ -46,6 +46,7 @@ preserve_order = ["indexmap"]
 [dependencies]
 serde = "1.0.145"
 indexmap = { version = "1.9.1", optional = true }
+toml_edit = { version = "0.17.1", path = "../toml_edit", features = ["serde"] }
 toml_datetime = { version = "0.5.0", path = "../toml_datetime", features = ["serde"] }
 serde_spanned = { version = "0.5.0", path = "../serde_spanned", features = ["serde"] }
 
diff --git a/crates/toml/examples/toml2json.rs b/crates/toml/examples/toml2json.rs
index 1b90c9fd..3660611c 100644
--- a/crates/toml/examples/toml2json.rs
+++ b/crates/toml/examples/toml2json.rs
@@ -13,7 +13,7 @@ fn main() {
     let mut input = String::new();
     if args.len() > 1 {
         let name = args.nth(1).unwrap();
-        File::open(&name)
+        File::open(name)
             .and_then(|mut f| f.read_to_string(&mut input))
             .unwrap();
     } else {
diff --git a/crates/toml/src/de.rs b/crates/toml/src/de.rs
index b2b931de..335009e4 100644
--- a/crates/toml/src/de.rs
+++ b/crates/toml/src/de.rs
@@ -4,40 +4,6 @@
 //! into Rust structures. Note that some top-level functions here are also
 //! provided at the top of the crate.
 
-use std::borrow::Cow;
-use std::collections::HashMap;
-use std::error;
-use std::f64;
-use std::fmt;
-use std::iter;
-use std::marker::PhantomData;
-use std::str;
-use std::vec;
-
-use serde::de;
-use serde::de::value::BorrowedStrDeserializer;
-use serde::de::IntoDeserializer;
-use toml_datetime::__unstable as datetime;
-
-use crate::tokens::{Error as TokenError, Span, Token, Tokenizer};
-
-/// Type Alias for a TOML Table pair
-type TablePair<'a> = ((Span, Cow<'a, str>), Value<'a>);
-
-/// Deserializes a byte slice into a type.
-///
-/// This function will attempt to interpret `bytes` as UTF-8 data and then
-/// deserialize `T` from the TOML document provided.
-pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T, Error>
-where
-    T: de::Deserialize<'de>,
-{
-    match str::from_utf8(bytes) {
-        Ok(s) => from_str(s),
-        Err(e) => Err(Error::custom(None, e.to_string())),
-    }
-}
-
 /// Deserializes a string into a type.
 ///
 /// This function will attempt to interpret `s` as a TOML document and
@@ -69,2205 +35,252 @@ where
 /// assert_eq!(config.title, "TOML Example");
 /// assert_eq!(config.owner.name, "Lisa");
 /// ```
-pub fn from_str<'de, T>(s: &'de str) -> Result<T, Error>
+pub fn from_str<T>(s: &'_ str) -> Result<T, Error>
 where
-    T: de::Deserialize<'de>,
+    T: serde::de::DeserializeOwned,
 {
-    let mut d = Deserializer::new(s);
-    let ret = T::deserialize(&mut d)?;
-    d.end()?;
-    Ok(ret)
+    T::deserialize(Deserializer::new(s))
 }
 
 /// Errors that can occur when deserializing a type.
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub struct Error {
-    inner: Box<ErrorInner>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-struct ErrorInner {
-    kind: ErrorKind,
-    line: Option<usize>,
-    col: usize,
-    at: Option<usize>,
-    message: String,
-    key: Vec<String>,
-}
-
-/// Errors that can occur when deserializing a type.
-#[derive(Debug, PartialEq, Eq, Clone)]
-#[non_exhaustive]
-enum ErrorKind {
-    /// EOF was reached when looking for a value
-    UnexpectedEof,
-
-    /// An invalid character not allowed in a string was found
-    InvalidCharInString(char),
-
-    /// An invalid character was found as an escape
-    InvalidEscape(char),
-
-    /// An invalid character was found in a hex escape
-    InvalidHexEscape(char),
-
-    /// An invalid escape value was specified in a hex escape in a string.
-    ///
-    /// Valid values are in the plane of unicode codepoints.
-    InvalidEscapeValue(u32),
-
-    /// A newline in a string was encountered when one was not allowed.
-    NewlineInString,
-
-    /// An unexpected character was encountered, typically when looking for a
-    /// value.
-    Unexpected(char),
-
-    /// An unterminated string was found where EOF was found before the ending
-    /// EOF mark.
-    UnterminatedString,
-
-    /// A newline was found in a table key.
-    NewlineInTableKey,
-
-    /// A number failed to parse
-    NumberInvalid,
-
-    /// A date or datetime was invalid
-    DateInvalid,
-
-    /// Wanted one sort of token, but found another.
-    Wanted {
-        /// Expected token type
-        expected: &'static str,
-        /// Actually found token type
-        found: &'static str,
-    },
-
-    /// A duplicate table definition was found.
-    DuplicateTable(String),
-
-    /// A previously defined table was redefined as an array.
-    RedefineAsArray,
-
-    /// An empty table key was found.
-    EmptyTableKey,
-
-    /// Multiline strings are not allowed for key
-    MultilineStringKey,
-
-    /// A custom error which could be generated when deserializing a particular
-    /// type.
-    Custom,
-
-    /// A tuple with a certain number of elements was expected but something
-    /// else was found.
-    ExpectedTuple(usize),
-
-    /// Expected table keys to be in increasing tuple index order, but something
-    /// else was found.
-    ExpectedTupleIndex {
-        /// Expected index.
-        expected: usize,
-        /// Key that was specified.
-        found: String,
-    },
-
-    /// An empty table was expected but entries were found
-    ExpectedEmptyTable,
-
-    /// Dotted key attempted to extend something that is not a table.
-    DottedKeyInvalidType,
-
-    /// An unexpected key was encountered.
-    ///
-    /// Used when deserializing a struct with a limited set of fields.
-    UnexpectedKeys {
-        /// The unexpected keys.
-        keys: Vec<String>,
-        /// Keys that may be specified.
-        available: &'static [&'static str],
-    },
-
-    /// Unquoted string was found when quoted one was expected
-    UnquotedString,
-}
-
-/// Deserialization implementation for TOML.
-pub struct Deserializer<'a> {
-    require_newline_after_table: bool,
-    allow_duplciate_after_longer_table: bool,
-    input: &'a str,
-    tokens: Tokenizer<'a>,
-}
-
-impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
-    type Error = Error;
-
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        let mut tables = self.tables()?;
-        let table_indices = build_table_indices(&tables);
-        let table_pindices = build_table_pindices(&tables);
-
-        let res = visitor.visit_map(MapVisitor {
-            values: Vec::new().into_iter().peekable(),
-            next_value: None,
-            depth: 0,
-            cur: 0,
-            cur_parent: 0,
-            max: tables.len(),
-            table_indices: &table_indices,
-            table_pindices: &table_pindices,
-            tables: &mut tables,
-            array: false,
-            de: self,
-        });
-        res.map_err(|mut err| {
-            // Errors originating from this library (toml), have an offset
-            // attached to them already. Other errors, like those originating
-            // from serde (like "missing field") or from a custom deserializer,
-            // do not have offsets on them. Here, we do a best guess at their
-            // location, by attributing them to the "current table" (the last
-            // item in `tables`).
-            err.fix_offset(|| tables.last().map(|table| table.at));
-            err.fix_linecol(|at| self.to_linecol(at));
-            err
-        })
-    }
-
-    // Called when the type to deserialize is an enum, as opposed to a field in the type.
-    fn deserialize_enum<V>(
-        self,
-        _name: &'static str,
-        _variants: &'static [&'static str],
-        visitor: V,
-    ) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        let (value, name) = self.string_or_table()?;
-        match value.e {
-            E::String(val) => visitor.visit_enum(val.into_deserializer()),
-            E::InlineTable(values) => {
-                if values.len() != 1 {
-                    Err(Error::from_kind(
-                        Some(value.start),
-                        ErrorKind::Wanted {
-                            expected: "exactly 1 element",
-                            found: if values.is_empty() {
-                                "zero elements"
-                            } else {
-                                "more than 1 element"
-                            },
-                        },
-                    ))
-                } else {
-                    visitor.visit_enum(InlineTableDeserializer {
-                        values: values.into_iter(),
-                        next_value: None,
-                    })
-                }
-            }
-            E::DottedTable(_) => visitor.visit_enum(DottedTableDeserializer {
-                name: name.expect("Expected table header to be passed."),
-                value,
-            }),
-            e => Err(Error::from_kind(
-                Some(value.start),
-                ErrorKind::Wanted {
-                    expected: "string or table",
-                    found: e.type_name(),
-                },
-            )),
-        }
-    }
-
-    fn deserialize_struct<V>(
-        self,
-        name: &'static str,
-        fields: &'static [&'static str],
-        visitor: V,
-    ) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        if name == serde_spanned::NAME
-            && fields
-                == [
-                    serde_spanned::START_FIELD,
-                    serde_spanned::END_FIELD,
-                    serde_spanned::VALUE_FIELD,
-                ]
-        {
-            let start = 0;
-            let end = self.input.len();
-
-            let res = visitor.visit_map(SpannedDeserializer {
-                phantom_data: PhantomData,
-                start: Some(start),
-                value: Some(self),
-                end: Some(end),
-            });
-            return res;
-        }
-
-        self.deserialize_any(visitor)
-    }
-
-    serde::forward_to_deserialize_any! {
-        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
-        bytes byte_buf map unit newtype_struct
-        ignored_any unit_struct tuple_struct tuple option identifier
-    }
+    inner: toml_edit::de::Error,
 }
 
-// Builds a datastructure that allows for efficient sublinear lookups.
-// The returned HashMap contains a mapping from table header (like [a.b.c])
-// to list of tables with that precise name. The tables are being identified
-// by their index in the passed slice. We use a list as the implementation
-// uses this data structure for arrays as well as tables,
-// so if any top level [[name]] array contains multiple entries,
-// there are multiple entries in the list.
-// The lookup is performed in the `SeqAccess` implementation of `MapVisitor`.
-// The lists are ordered, which we exploit in the search code by using
-// bisection.
-fn build_table_indices<'de>(tables: &[Table<'de>]) -> HashMap<Vec<Cow<'de, str>>, Vec<usize>> {
-    let mut res = HashMap::new();
-    for (i, table) in tables.iter().enumerate() {
-        let header = table.header.iter().map(|v| v.1.clone()).collect::<Vec<_>>();
-        res.entry(header).or_insert_with(Vec::new).push(i);
+impl Error {
+    fn new(inner: toml_edit::de::Error) -> Self {
+        Self { inner }
     }
-    res
-}
 
-// Builds a datastructure that allows for efficient sublinear lookups.
-// The returned HashMap contains a mapping from table header (like [a.b.c])
-// to list of tables whose name at least starts with the specified
-// name. So searching for [a.b] would give both [a.b.c.d] as well as [a.b.e].
-// The tables are being identified by their index in the passed slice.
-//
-// A list is used for two reasons: First, the implementation also
-// stores arrays in the same data structure and any top level array
-// of size 2 or greater creates multiple entries in the list with the
-// same shared name. Second, there can be multiple tables sharing
-// the same prefix.
-//
-// The lookup is performed in the `MapAccess` implementation of `MapVisitor`.
-// The lists are ordered, which we exploit in the search code by using
-// bisection.
-fn build_table_pindices<'de>(tables: &[Table<'de>]) -> HashMap<Vec<Cow<'de, str>>, Vec<usize>> {
-    let mut res = HashMap::new();
-    for (i, table) in tables.iter().enumerate() {
-        let header = table.header.iter().map(|v| v.1.clone()).collect::<Vec<_>>();
-        for len in 0..=header.len() {
-            res.entry(header[..len].to_owned())
-                .or_insert_with(Vec::new)
-                .push(i);
-        }
+    /// The start/end index into the original document where the error occurred
+    pub fn span(&self) -> Option<std::ops::Range<usize>> {
+        self.inner.span()
     }
-    res
-}
 
-fn headers_equal<'a, 'b>(hdr_a: &[(Span, Cow<'a, str>)], hdr_b: &[(Span, Cow<'b, str>)]) -> bool {
-    if hdr_a.len() != hdr_b.len() {
-        return false;
+    /// Produces a (line, column) pair of the position of the error if available
+    ///
+    /// All indexes are 0-based.
+    #[deprecated(since = "0.18.0", note = "See instead `Error::span`")]
+    pub fn line_col(&self) -> Option<(usize, usize)> {
+        #[allow(deprecated)]
+        self.inner.line_col()
     }
-    hdr_a.iter().zip(hdr_b.iter()).all(|(h1, h2)| h1.1 == h2.1)
-}
-
-struct Table<'a> {
-    at: usize,
-    header: Vec<(Span, Cow<'a, str>)>,
-    values: Option<Vec<TablePair<'a>>>,
-    array: bool,
-}
-
-struct MapVisitor<'de, 'b> {
-    values: iter::Peekable<vec::IntoIter<TablePair<'de>>>,
-    next_value: Option<TablePair<'de>>,
-    depth: usize,
-    cur: usize,
-    cur_parent: usize,
-    max: usize,
-    table_indices: &'b HashMap<Vec<Cow<'de, str>>, Vec<usize>>,
-    table_pindices: &'b HashMap<Vec<Cow<'de, str>>, Vec<usize>>,
-    tables: &'b mut [Table<'de>],
-    array: bool,
-    de: &'b mut Deserializer<'de>,
 }
 
-impl<'de, 'b> de::MapAccess<'de> for MapVisitor<'de, 'b> {
-    type Error = Error;
-
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+impl serde::de::Error for Error {
+    fn custom<T>(msg: T) -> Self
     where
-        K: de::DeserializeSeed<'de>,
+        T: std::fmt::Display,
     {
-        if self.cur_parent == self.max || self.cur == self.max {
-            return Ok(None);
-        }
-
-        loop {
-            assert!(self.next_value.is_none());
-            if let Some((key, value)) = self.values.next() {
-                let ret = seed.deserialize(StrDeserializer::spanned(key.clone()))?;
-                self.next_value = Some((key, value));
-                return Ok(Some(ret));
-            }
-
-            let next_table = {
-                let prefix_stripped = self.tables[self.cur_parent].header[..self.depth]
-                    .iter()
-                    .map(|v| v.1.clone())
-                    .collect::<Vec<_>>();
-                self.table_pindices
-                    .get(&prefix_stripped)
-                    .and_then(|entries| {
-                        let start = entries.binary_search(&self.cur).unwrap_or_else(|v| v);
-                        if start == entries.len() || entries[start] < self.cur {
-                            return None;
-                        }
-                        entries[start..]
-                            .iter()
-                            .filter_map(|i| if *i < self.max { Some(*i) } else { None })
-                            .map(|i| (i, &self.tables[i]))
-                            .find(|(_, table)| table.values.is_some())
-                            .map(|p| p.0)
-                    })
-            };
-
-            let pos = match next_table {
-                Some(pos) => pos,
-                None => return Ok(None),
-            };
-            self.cur = pos;
-
-            // Test to see if we're duplicating our parent's table, and if so
-            // then this is an error in the toml format
-            if self.cur_parent != pos {
-                if headers_equal(
-                    &self.tables[self.cur_parent].header,
-                    &self.tables[pos].header,
-                ) {
-                    let at = self.tables[pos].at;
-                    let name = self.tables[pos]
-                        .header
-                        .iter()
-                        .map(|k| k.1.to_owned())
-                        .collect::<Vec<_>>()
-                        .join(".");
-                    return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
-                }
-
-                // If we're here we know we should share the same prefix, and if
-                // the longer table was defined first then we want to narrow
-                // down our parent's length if possible to ensure that we catch
-                // duplicate tables defined afterwards.
-                if !self.de.allow_duplciate_after_longer_table {
-                    let parent_len = self.tables[self.cur_parent].header.len();
-                    let cur_len = self.tables[pos].header.len();
-                    if cur_len < parent_len {
-                        self.cur_parent = pos;
-                    }
-                }
-            }
-
-            let table = &mut self.tables[pos];
-
-            // If we're not yet at the appropriate depth for this table then we
-            // just next the next portion of its header and then continue
-            // decoding.
-            if self.depth != table.header.len() {
-                let key = &table.header[self.depth];
-                let key = seed.deserialize(StrDeserializer::spanned(key.clone()))?;
-                return Ok(Some(key));
-            }
-
-            // Rule out cases like:
-            //
-            //      [[foo.bar]]
-            //      [[foo]]
-            if table.array {
-                let kind = ErrorKind::RedefineAsArray;
-                return Err(self.de.error(table.at, kind));
-            }
-
-            self.values = table
-                .values
-                .take()
-                .expect("Unable to read table values")
-                .into_iter()
-                .peekable();
-        }
+        Error::new(toml_edit::de::Error::custom(msg))
     }
+}
 
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        if let Some((k, v)) = self.next_value.take() {
-            match seed.deserialize(ValueDeserializer::new(v)) {
-                Ok(v) => return Ok(v),
-                Err(mut e) => {
-                    e.add_key_context(&k.1);
-                    return Err(e);
-                }
-            }
-        }
-
-        let array =
-            self.tables[self.cur].array && self.depth == self.tables[self.cur].header.len() - 1;
-        self.cur += 1;
-        let res = seed.deserialize(MapVisitor {
-            values: Vec::new().into_iter().peekable(),
-            next_value: None,
-            depth: self.depth + if array { 0 } else { 1 },
-            cur_parent: self.cur - 1,
-            cur: 0,
-            max: self.max,
-            array,
-            table_indices: self.table_indices,
-            table_pindices: self.table_pindices,
-            tables: &mut *self.tables,
-            de: &mut *self.de,
-        });
-        res.map_err(|mut e| {
-            e.add_key_context(&self.tables[self.cur - 1].header[self.depth].1);
-            e
-        })
+impl std::fmt::Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.inner.fmt(f)
     }
 }
 
-impl<'de, 'b> de::SeqAccess<'de> for MapVisitor<'de, 'b> {
-    type Error = Error;
-
-    fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
-    where
-        K: de::DeserializeSeed<'de>,
-    {
-        assert!(self.next_value.is_none());
-        assert!(self.values.next().is_none());
-
-        if self.cur_parent == self.max {
-            return Ok(None);
-        }
+impl std::error::Error for Error {}
 
-        let header_stripped = self.tables[self.cur_parent]
-            .header
-            .iter()
-            .map(|v| v.1.clone())
-            .collect::<Vec<_>>();
-        let start_idx = self.cur_parent + 1;
-        let next = self
-            .table_indices
-            .get(&header_stripped)
-            .and_then(|entries| {
-                let start = entries.binary_search(&start_idx).unwrap_or_else(|v| v);
-                if start == entries.len() || entries[start] < start_idx {
-                    return None;
-                }
-                entries[start..]
-                    .iter()
-                    .filter_map(|i| if *i < self.max { Some(*i) } else { None })
-                    .map(|i| (i, &self.tables[i]))
-                    .find(|(_, table)| table.array)
-                    .map(|p| p.0)
-            })
-            .unwrap_or(self.max);
+/// Deserialization TOML document
+pub struct Deserializer<'a> {
+    input: &'a str,
+}
 
-        let ret = seed.deserialize(MapVisitor {
-            values: self.tables[self.cur_parent]
-                .values
-                .take()
-                .expect("Unable to read table values")
-                .into_iter()
-                .peekable(),
-            next_value: None,
-            depth: self.depth + 1,
-            cur_parent: self.cur_parent,
-            max: next,
-            cur: 0,
-            array: false,
-            table_indices: self.table_indices,
-            table_pindices: self.table_pindices,
-            tables: self.tables,
-            de: self.de,
-        })?;
-        self.cur_parent = next;
-        Ok(Some(ret))
+impl<'a> Deserializer<'a> {
+    /// Deserialization implementation for TOML.
+    pub fn new(input: &'a str) -> Self {
+        Self { input }
     }
 }
 
-impl<'de, 'b> de::Deserializer<'de> for MapVisitor<'de, 'b> {
+impl<'de, 'a> serde::Deserializer<'de> for Deserializer<'a> {
     type Error = Error;
 
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        if self.array {
-            visitor.visit_seq(self)
-        } else {
-            visitor.visit_map(self)
-        }
+        let inner = self
+            .input
+            .parse::<toml_edit::de::Deserializer>()
+            .map_err(Error::new)?;
+        inner.deserialize_any(visitor).map_err(Error::new)
     }
 
     // `None` is interpreted as a missing field so be sure to implement `Some`
     // as a present field.
     fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        visitor.visit_some(self)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::Deserializer>()
+            .map_err(Error::new)?;
+        inner.deserialize_option(visitor).map_err(Error::new)
     }
 
     fn deserialize_newtype_struct<V>(
         self,
-        _name: &'static str,
+        name: &'static str,
         visitor: V,
     ) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        visitor.visit_newtype_struct(self)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::Deserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_newtype_struct(name, visitor)
+            .map_err(Error::new)
     }
 
     fn deserialize_struct<V>(
-        mut self,
+        self,
         name: &'static str,
         fields: &'static [&'static str],
         visitor: V,
     ) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        if name == serde_spanned::NAME
-            && fields
-                == [
-                    serde_spanned::START_FIELD,
-                    serde_spanned::END_FIELD,
-                    serde_spanned::VALUE_FIELD,
-                ]
-            && !(self.array && self.values.peek().is_some())
-        {
-            // TODO we can't actually emit spans here for the *entire* table/array
-            // due to the format that toml uses. Setting the start and end to 0 is
-            // *detectable* (and no reasonable span would look like that),
-            // it would be better to expose this in the API via proper
-            // ADTs like Option<T>.
-            let start = 0;
-            let end = 0;
-
-            let res = visitor.visit_map(SpannedDeserializer {
-                phantom_data: PhantomData,
-                start: Some(start),
-                value: Some(self),
-                end: Some(end),
-            });
-            return res;
-        }
-
-        self.deserialize_any(visitor)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::Deserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_struct(name, fields, visitor)
+            .map_err(Error::new)
     }
 
+    // Called when the type to deserialize is an enum, as opposed to a field in the type.
     fn deserialize_enum<V>(
-        self,
-        _name: &'static str,
-        _variants: &'static [&'static str],
-        visitor: V,
-    ) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        if self.tables.len() != 1 {
-            return Err(Error::custom(
-                Some(self.cur),
-                "enum table must contain exactly one table".into(),
-            ));
-        }
-        let table = &mut self.tables[0];
-        let values = table.values.take().expect("table has no values?");
-        if table.header.is_empty() {
-            return Err(self.de.error(self.cur, ErrorKind::EmptyTableKey));
-        }
-        let name = table.header[table.header.len() - 1].1.to_owned();
-        visitor.visit_enum(DottedTableDeserializer {
-            name,
-            value: Value {
-                e: E::DottedTable(values),
-                start: 0,
-                end: 0,
-            },
-        })
-    }
-
-    serde::forward_to_deserialize_any! {
-        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
-        bytes byte_buf map unit identifier
-        ignored_any unit_struct tuple_struct tuple
-    }
-}
-
-struct StrDeserializer<'a> {
-    span: Option<Span>,
-    key: Cow<'a, str>,
-}
-
-impl<'a> StrDeserializer<'a> {
-    fn spanned(inner: (Span, Cow<'a, str>)) -> StrDeserializer<'a> {
-        StrDeserializer {
-            span: Some(inner.0),
-            key: inner.1,
-        }
-    }
-    fn new(key: Cow<'a, str>) -> StrDeserializer<'a> {
-        StrDeserializer { span: None, key }
-    }
-}
-
-impl<'a> de::IntoDeserializer<'a, Error> for StrDeserializer<'a> {
-    type Deserializer = Self;
-
-    fn into_deserializer(self) -> Self::Deserializer {
-        self
-    }
-}
-
-impl<'de> de::Deserializer<'de> for StrDeserializer<'de> {
-    type Error = Error;
-
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        match self.key {
-            Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
-            Cow::Owned(s) => visitor.visit_string(s),
-        }
-    }
-
-    fn deserialize_struct<V>(
         self,
         name: &'static str,
-        fields: &'static [&'static str],
+        variants: &'static [&'static str],
         visitor: V,
     ) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        if name == serde_spanned::NAME
-            && fields
-                == [
-                    serde_spanned::START_FIELD,
-                    serde_spanned::END_FIELD,
-                    serde_spanned::VALUE_FIELD,
-                ]
-        {
-            if let Some(span) = self.span {
-                return visitor.visit_map(SpannedDeserializer {
-                    phantom_data: PhantomData,
-                    start: Some(span.start),
-                    value: Some(StrDeserializer::new(self.key)),
-                    end: Some(span.end),
-                });
-            }
-        }
-        self.deserialize_any(visitor)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::Deserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_enum(name, variants, visitor)
+            .map_err(Error::new)
     }
 
     serde::forward_to_deserialize_any! {
         bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
-        bytes byte_buf map option unit newtype_struct
-        ignored_any unit_struct tuple_struct tuple enum identifier
+        bytes byte_buf map unit
+        ignored_any unit_struct tuple_struct tuple identifier
     }
 }
 
-struct ValueDeserializer<'a> {
-    value: Value<'a>,
-    validate_struct_keys: bool,
+/// Deserialization TOML value
+pub struct ValueDeserializer<'a> {
+    input: &'a str,
 }
 
 impl<'a> ValueDeserializer<'a> {
-    fn new(value: Value<'a>) -> ValueDeserializer<'a> {
-        ValueDeserializer {
-            value,
-            validate_struct_keys: false,
-        }
-    }
-
-    fn with_struct_key_validation(mut self) -> Self {
-        self.validate_struct_keys = true;
-        self
+    /// Deserialization implementation for TOML.
+    pub fn new(input: &'a str) -> Self {
+        Self { input }
     }
 }
 
-impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
+impl<'de, 'a> serde::Deserializer<'de> for ValueDeserializer<'a> {
     type Error = Error;
 
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        let start = self.value.start;
-        let res = match self.value.e {
-            E::Integer(i) => visitor.visit_i64(i),
-            E::Boolean(b) => visitor.visit_bool(b),
-            E::Float(f) => visitor.visit_f64(f),
-            E::String(Cow::Borrowed(s)) => visitor.visit_borrowed_str(s),
-            E::String(Cow::Owned(s)) => visitor.visit_string(s),
-            E::Datetime(s) => visitor.visit_map(DatetimeDeserializer {
-                date: s,
-                visited: false,
-            }),
-            E::Array(values) => {
-                let mut s = de::value::SeqDeserializer::new(values.into_iter());
-                let ret = visitor.visit_seq(&mut s)?;
-                s.end()?;
-                Ok(ret)
-            }
-            E::InlineTable(values) | E::DottedTable(values) => {
-                visitor.visit_map(InlineTableDeserializer {
-                    values: values.into_iter(),
-                    next_value: None,
-                })
-            }
-        };
-        res.map_err(|mut err| {
-            // Attribute the error to whatever value returned the error.
-            err.fix_offset(|| Some(start));
-            err
-        })
-    }
-
-    fn deserialize_struct<V>(
-        self,
-        name: &'static str,
-        fields: &'static [&'static str],
-        visitor: V,
-    ) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        if name == datetime::NAME && fields == [datetime::FIELD] {
-            if let E::Datetime(s) = self.value.e {
-                return visitor.visit_map(DatetimeDeserializer {
-                    date: s,
-                    visited: false,
-                });
-            }
-        }
-
-        if self.validate_struct_keys {
-            match self.value.e {
-                E::InlineTable(ref values) | E::DottedTable(ref values) => {
-                    let extra_fields = values
-                        .iter()
-                        .filter_map(|key_value| {
-                            let (ref key, ref _val) = *key_value;
-                            if !fields.contains(&&*(key.1)) {
-                                Some(key.clone())
-                            } else {
-                                None
-                            }
-                        })
-                        .collect::<Vec<_>>();
-
-                    if !extra_fields.is_empty() {
-                        return Err(Error::from_kind(
-                            Some(self.value.start),
-                            ErrorKind::UnexpectedKeys {
-                                keys: extra_fields
-                                    .iter()
-                                    .map(|k| k.1.to_string())
-                                    .collect::<Vec<_>>(),
-                                available: fields,
-                            },
-                        ));
-                    }
-                }
-                _ => {}
-            }
-        }
-
-        if name == serde_spanned::NAME
-            && fields
-                == [
-                    serde_spanned::START_FIELD,
-                    serde_spanned::END_FIELD,
-                    serde_spanned::VALUE_FIELD,
-                ]
-        {
-            let start = self.value.start;
-            let end = self.value.end;
-
-            return visitor.visit_map(SpannedDeserializer {
-                phantom_data: PhantomData,
-                start: Some(start),
-                value: Some(self.value),
-                end: Some(end),
-            });
-        }
-
-        self.deserialize_any(visitor)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::ValueDeserializer>()
+            .map_err(Error::new)?;
+        inner.deserialize_any(visitor).map_err(Error::new)
     }
 
     // `None` is interpreted as a missing field so be sure to implement `Some`
     // as a present field.
     fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        visitor.visit_some(self)
+        let inner = self
+            .input
+            .parse::<toml_edit::de::ValueDeserializer>()
+            .map_err(Error::new)?;
+        inner.deserialize_option(visitor).map_err(Error::new)
     }
 
-    fn deserialize_enum<V>(
+    fn deserialize_newtype_struct<V>(
         self,
-        _name: &'static str,
-        _variants: &'static [&'static str],
+        name: &'static str,
         visitor: V,
     ) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        match self.value.e {
-            E::String(val) => visitor.visit_enum(val.into_deserializer()),
-            E::InlineTable(values) => {
-                if values.len() != 1 {
-                    Err(Error::from_kind(
-                        Some(self.value.start),
-                        ErrorKind::Wanted {
-                            expected: "exactly 1 element",
-                            found: if values.is_empty() {
-                                "zero elements"
-                            } else {
-                                "more than 1 element"
-                            },
-                        },
-                    ))
-                } else {
-                    visitor.visit_enum(InlineTableDeserializer {
-                        values: values.into_iter(),
-                        next_value: None,
-                    })
-                }
-            }
-            e => Err(Error::from_kind(
-                Some(self.value.start),
-                ErrorKind::Wanted {
-                    expected: "string or inline table",
-                    found: e.type_name(),
-                },
-            )),
-        }
+        let inner = self
+            .input
+            .parse::<toml_edit::de::ValueDeserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_newtype_struct(name, visitor)
+            .map_err(Error::new)
     }
 
-    fn deserialize_newtype_struct<V>(
+    fn deserialize_struct<V>(
         self,
-        _name: &'static str,
+        name: &'static str,
+        fields: &'static [&'static str],
         visitor: V,
     ) -> Result<V::Value, Error>
     where
-        V: de::Visitor<'de>,
-    {
-        visitor.visit_newtype_struct(self)
-    }
-
-    serde::forward_to_deserialize_any! {
-        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
-        bytes byte_buf map unit identifier
-        ignored_any unit_struct tuple_struct tuple
-    }
-}
-
-impl<'de, 'b> de::IntoDeserializer<'de, Error> for MapVisitor<'de, 'b> {
-    type Deserializer = MapVisitor<'de, 'b>;
-
-    fn into_deserializer(self) -> Self::Deserializer {
-        self
-    }
-}
-
-impl<'de, 'b> de::IntoDeserializer<'de, Error> for &'b mut Deserializer<'de> {
-    type Deserializer = Self;
-
-    fn into_deserializer(self) -> Self::Deserializer {
-        self
-    }
-}
-
-impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> {
-    type Deserializer = ValueDeserializer<'de>;
-
-    fn into_deserializer(self) -> Self::Deserializer {
-        ValueDeserializer::new(self)
-    }
-}
-
-struct SpannedDeserializer<'de, T: de::IntoDeserializer<'de, Error>> {
-    phantom_data: PhantomData<&'de ()>,
-    start: Option<usize>,
-    end: Option<usize>,
-    value: Option<T>,
-}
-
-impl<'de, T> de::MapAccess<'de> for SpannedDeserializer<'de, T>
-where
-    T: de::IntoDeserializer<'de, Error>,
-{
-    type Error = Error;
-
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
-    where
-        K: de::DeserializeSeed<'de>,
-    {
-        if self.start.is_some() {
-            seed.deserialize(BorrowedStrDeserializer::new(serde_spanned::START_FIELD))
-                .map(Some)
-        } else if self.end.is_some() {
-            seed.deserialize(BorrowedStrDeserializer::new(serde_spanned::END_FIELD))
-                .map(Some)
-        } else if self.value.is_some() {
-            seed.deserialize(BorrowedStrDeserializer::new(serde_spanned::VALUE_FIELD))
-                .map(Some)
-        } else {
-            Ok(None)
-        }
-    }
-
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        if let Some(start) = self.start.take() {
-            seed.deserialize(start.into_deserializer())
-        } else if let Some(end) = self.end.take() {
-            seed.deserialize(end.into_deserializer())
-        } else if let Some(value) = self.value.take() {
-            seed.deserialize(value.into_deserializer())
-        } else {
-            panic!("next_value_seed called before next_key_seed")
-        }
-    }
-}
-
-struct DatetimeDeserializer<'a> {
-    visited: bool,
-    date: &'a str,
-}
-
-impl<'de> de::MapAccess<'de> for DatetimeDeserializer<'de> {
-    type Error = Error;
-
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
-    where
-        K: de::DeserializeSeed<'de>,
-    {
-        if self.visited {
-            return Ok(None);
-        }
-        self.visited = true;
-        seed.deserialize(DatetimeFieldDeserializer).map(Some)
-    }
-
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        seed.deserialize(StrDeserializer::new(self.date.into()))
-    }
-}
-
-struct DatetimeFieldDeserializer;
-
-impl<'de> de::Deserializer<'de> for DatetimeFieldDeserializer {
-    type Error = Error;
-
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        visitor.visit_borrowed_str(datetime::FIELD)
-    }
-
-    serde::forward_to_deserialize_any! {
-        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
-        bytes byte_buf map struct option unit newtype_struct
-        ignored_any unit_struct tuple_struct tuple enum identifier
-    }
-}
-
-struct DottedTableDeserializer<'a> {
-    name: Cow<'a, str>,
-    value: Value<'a>,
-}
-
-impl<'de> de::EnumAccess<'de> for DottedTableDeserializer<'de> {
-    type Error = Error;
-    type Variant = TableEnumDeserializer<'de>;
-
-    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        let (name, value) = (self.name, self.value);
-        seed.deserialize(StrDeserializer::new(name))
-            .map(|val| (val, TableEnumDeserializer { value }))
-    }
-}
-
-struct InlineTableDeserializer<'a> {
-    values: vec::IntoIter<TablePair<'a>>,
-    next_value: Option<Value<'a>>,
-}
-
-impl<'de> de::MapAccess<'de> for InlineTableDeserializer<'de> {
-    type Error = Error;
-
-    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
-    where
-        K: de::DeserializeSeed<'de>,
-    {
-        let (key, value) = match self.values.next() {
-            Some(pair) => pair,
-            None => return Ok(None),
-        };
-        self.next_value = Some(value);
-        seed.deserialize(StrDeserializer::spanned(key)).map(Some)
-    }
-
-    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        let value = self.next_value.take().expect("Unable to read table values");
-        seed.deserialize(ValueDeserializer::new(value))
-    }
-}
-
-impl<'de> de::EnumAccess<'de> for InlineTableDeserializer<'de> {
-    type Error = Error;
-    type Variant = TableEnumDeserializer<'de>;
-
-    fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
-    where
-        V: de::DeserializeSeed<'de>,
-    {
-        let (key, value) = match self.values.next() {
-            Some(pair) => pair,
-            None => {
-                return Err(Error::from_kind(
-                    None, // FIXME: How do we get an offset here?
-                    ErrorKind::Wanted {
-                        expected: "table with exactly 1 entry",
-                        found: "empty table",
-                    },
-                ));
-            }
-        };
-
-        seed.deserialize(StrDeserializer::new(key.1))
-            .map(|val| (val, TableEnumDeserializer { value }))
-    }
-}
-
-/// Deserializes table values into enum variants.
-struct TableEnumDeserializer<'a> {
-    value: Value<'a>,
-}
-
-impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> {
-    type Error = Error;
-
-    fn unit_variant(self) -> Result<(), Self::Error> {
-        match self.value.e {
-            E::InlineTable(values) | E::DottedTable(values) => {
-                if values.is_empty() {
-                    Ok(())
-                } else {
-                    Err(Error::from_kind(
-                        Some(self.value.start),
-                        ErrorKind::ExpectedEmptyTable,
-                    ))
-                }
-            }
-            e => Err(Error::from_kind(
-                Some(self.value.start),
-                ErrorKind::Wanted {
-                    expected: "table",
-                    found: e.type_name(),
-                },
-            )),
-        }
-    }
-
-    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
-    where
-        T: de::DeserializeSeed<'de>,
+        V: serde::de::Visitor<'de>,
     {
-        seed.deserialize(ValueDeserializer::new(self.value))
+        let inner = self
+            .input
+            .parse::<toml_edit::de::ValueDeserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_struct(name, fields, visitor)
+            .map_err(Error::new)
     }
 
-    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        match self.value.e {
-            E::InlineTable(values) | E::DottedTable(values) => {
-                let tuple_values = values
-                    .into_iter()
-                    .enumerate()
-                    .map(|(index, (key, value))| match key.1.parse::<usize>() {
-                        Ok(key_index) if key_index == index => Ok(value),
-                        Ok(_) | Err(_) => Err(Error::from_kind(
-                            Some(key.0.start),
-                            ErrorKind::ExpectedTupleIndex {
-                                expected: index,
-                                found: key.1.to_string(),
-                            },
-                        )),
-                    })
-                    // Fold all values into a `Vec`, or return the first error.
-                    .fold(Ok(Vec::with_capacity(len)), |result, value_result| {
-                        result.and_then(move |mut tuple_values| match value_result {
-                            Ok(value) => {
-                                tuple_values.push(value);
-                                Ok(tuple_values)
-                            }
-                            // `Result<de::Value, Self::Error>` to `Result<Vec<_>, Self::Error>`
-                            Err(e) => Err(e),
-                        })
-                    })?;
-
-                if tuple_values.len() == len {
-                    de::Deserializer::deserialize_seq(
-                        ValueDeserializer::new(Value {
-                            e: E::Array(tuple_values),
-                            start: self.value.start,
-                            end: self.value.end,
-                        }),
-                        visitor,
-                    )
-                } else {
-                    Err(Error::from_kind(
-                        Some(self.value.start),
-                        ErrorKind::ExpectedTuple(len),
-                    ))
-                }
-            }
-            e => Err(Error::from_kind(
-                Some(self.value.start),
-                ErrorKind::Wanted {
-                    expected: "table",
-                    found: e.type_name(),
-                },
-            )),
-        }
-    }
-
-    fn struct_variant<V>(
+    // Called when the type to deserialize is an enum, as opposed to a field in the type.
+    fn deserialize_enum<V>(
         self,
-        fields: &'static [&'static str],
+        name: &'static str,
+        variants: &'static [&'static str],
         visitor: V,
-    ) -> Result<V::Value, Self::Error>
-    where
-        V: de::Visitor<'de>,
-    {
-        de::Deserializer::deserialize_struct(
-            ValueDeserializer::new(self.value).with_struct_key_validation(),
-            "", // TODO: this should be the variant name
-            fields,
-            visitor,
-        )
-    }
-}
-
-impl<'a> Deserializer<'a> {
-    /// Creates a new deserializer which will be deserializing the string
-    /// provided.
-    pub fn new(input: &'a str) -> Deserializer<'a> {
-        Deserializer {
-            tokens: Tokenizer::new(input),
-            input,
-            require_newline_after_table: true,
-            allow_duplciate_after_longer_table: false,
-        }
-    }
-
-    /// The `Deserializer::end` method should be called after a value has been
-    /// fully deserialized.  This allows the `Deserializer` to validate that the
-    /// input stream is at the end or that it only has trailing
-    /// whitespace/comments.
-    pub fn end(&mut self) -> Result<(), Error> {
-        Ok(())
-    }
-
-    #[doc(hidden)]
-    #[deprecated(since = "0.5.10")]
-    pub fn set_require_newline_after_table(&mut self, require: bool) {
-        self.require_newline_after_table = require;
-    }
-
-    #[doc(hidden)]
-    #[deprecated(since = "0.5.10")]
-    pub fn set_allow_duplicate_after_longer_table(&mut self, allow: bool) {
-        self.allow_duplciate_after_longer_table = allow;
-    }
-
-    fn tables(&mut self) -> Result<Vec<Table<'a>>, Error> {
-        let mut tables = Vec::new();
-        let mut cur_table = Table {
-            at: 0,
-            header: Vec::new(),
-            values: None,
-            array: false,
-        };
-
-        while let Some(line) = self.line()? {
-            match line {
-                Line::Table {
-                    at,
-                    mut header,
-                    array,
-                } => {
-                    if !cur_table.header.is_empty() || cur_table.values.is_some() {
-                        tables.push(cur_table);
-                    }
-                    cur_table = Table {
-                        at,
-                        header: Vec::new(),
-                        values: Some(Vec::new()),
-                        array,
-                    };
-                    loop {
-                        let part = header.next().map_err(|e| self.token_error(e));
-                        match part? {
-                            Some(part) => cur_table.header.push(part),
-                            None => break,
-                        }
-                    }
-                }
-                Line::KeyValue(key, value) => {
-                    if cur_table.values.is_none() {
-                        cur_table.values = Some(Vec::new());
-                    }
-                    self.add_dotted_key(key, value, cur_table.values.as_mut().unwrap())?;
-                }
-            }
-        }
-        if !cur_table.header.is_empty() || cur_table.values.is_some() {
-            tables.push(cur_table);
-        }
-        Ok(tables)
-    }
-
-    fn line(&mut self) -> Result<Option<Line<'a>>, Error> {
-        loop {
-            self.eat_whitespace()?;
-            if self.eat_comment()? {
-                continue;
-            }
-            if self.eat(Token::Newline)? {
-                continue;
-            }
-            break;
-        }
-
-        match self.peek()? {
-            Some((_, Token::LeftBracket)) => self.table_header().map(Some),
-            Some(_) => self.key_value().map(Some),
-            None => Ok(None),
-        }
-    }
-
-    fn table_header(&mut self) -> Result<Line<'a>, Error> {
-        let start = self.tokens.current();
-        self.expect(Token::LeftBracket)?;
-        let array = self.eat(Token::LeftBracket)?;
-        let ret = Header::new(self.tokens.clone(), array, self.require_newline_after_table);
-        if self.require_newline_after_table {
-            self.tokens.skip_to_newline();
-        } else {
-            loop {
-                match self.next()? {
-                    Some((_, Token::RightBracket)) => {
-                        if array {
-                            self.eat(Token::RightBracket)?;
-                        }
-                        break;
-                    }
-                    Some((_, Token::Newline)) | None => break,
-                    _ => {}
-                }
-            }
-            self.eat_whitespace()?;
-        }
-        Ok(Line::Table {
-            at: start,
-            header: ret,
-            array,
-        })
-    }
-
-    fn key_value(&mut self) -> Result<Line<'a>, Error> {
-        let key = self.dotted_key()?;
-        self.eat_whitespace()?;
-        self.expect(Token::Equals)?;
-        self.eat_whitespace()?;
-
-        let value = self.value()?;
-        self.eat_whitespace()?;
-        if !self.eat_comment()? {
-            self.eat_newline_or_eof()?;
-        }
-
-        Ok(Line::KeyValue(key, value))
-    }
-
-    fn value(&mut self) -> Result<Value<'a>, Error> {
-        let at = self.tokens.current();
-        let value = match self.next()? {
-            Some((Span { start, end }, Token::String { val, .. })) => Value {
-                e: E::String(val),
-                start,
-                end,
-            },
-            Some((Span { start, end }, Token::Keylike("true"))) => Value {
-                e: E::Boolean(true),
-                start,
-                end,
-            },
-            Some((Span { start, end }, Token::Keylike("false"))) => Value {
-                e: E::Boolean(false),
-                start,
-                end,
-            },
-            Some((span, Token::Keylike(key))) => self.parse_keylike(at, span, key)?,
-            Some((span, Token::Plus)) => self.number_leading_plus(span)?,
-            Some((Span { start, .. }, Token::LeftBrace)) => {
-                self.inline_table().map(|(Span { end, .. }, table)| Value {
-                    e: E::InlineTable(table),
-                    start,
-                    end,
-                })?
-            }
-            Some((Span { start, .. }, Token::LeftBracket)) => {
-                self.array().map(|(Span { end, .. }, array)| Value {
-                    e: E::Array(array),
-                    start,
-                    end,
-                })?
-            }
-            Some(token) => {
-                return Err(self.error(
-                    at,
-                    ErrorKind::Wanted {
-                        expected: "a value",
-                        found: token.1.describe(),
-                    },
-                ));
-            }
-            None => return Err(self.eof()),
-        };
-        Ok(value)
-    }
-
-    fn parse_keylike(&mut self, at: usize, span: Span, key: &'a str) -> Result<Value<'a>, Error> {
-        if key == "inf" || key == "nan" {
-            return self.number_or_date(span, key);
-        }
-
-        let first_char = key.chars().next().expect("key should not be empty here");
-        match first_char {
-            '-' | '0'..='9' => self.number_or_date(span, key),
-            _ => Err(self.error(at, ErrorKind::UnquotedString)),
-        }
-    }
-
-    fn number_or_date(&mut self, span: Span, s: &'a str) -> Result<Value<'a>, Error> {
-        if s.contains('T')
-            || s.contains('t')
-            || (s.len() > 1 && s[1..].contains('-') && !s.contains("e-") && !s.contains("E-"))
-        {
-            self.datetime(span, s, false)
-                .map(|(Span { start, end }, d)| Value {
-                    e: E::Datetime(d),
-                    start,
-                    end,
-                })
-        } else if self.eat(Token::Colon)? {
-            self.datetime(span, s, true)
-                .map(|(Span { start, end }, d)| Value {
-                    e: E::Datetime(d),
-                    start,
-                    end,
-                })
-        } else {
-            self.number(span, s)
-        }
-    }
-
-    /// Returns a string or table value type.
-    ///
-    /// Used to deserialize enums. Unit enums may be represented as a string or a table, all other
-    /// structures (tuple, newtype, struct) must be represented as a table.
-    fn string_or_table(&mut self) -> Result<(Value<'a>, Option<Cow<'a, str>>), Error> {
-        match self.peek()? {
-            Some((span, Token::LeftBracket)) => {
-                let tables = self.tables()?;
-                if tables.len() != 1 {
-                    return Err(Error::from_kind(
-                        Some(span.start),
-                        ErrorKind::Wanted {
-                            expected: "exactly 1 table",
-                            found: if tables.is_empty() {
-                                "zero tables"
-                            } else {
-                                "more than 1 table"
-                            },
-                        },
-                    ));
-                }
-
-                let table = tables
-                    .into_iter()
-                    .next()
-                    .expect("Expected exactly one table");
-                let header = table
-                    .header
-                    .last()
-                    .expect("Expected at least one header value for table.");
-
-                let start = table.at;
-                let end = table
-                    .values
-                    .as_ref()
-                    .and_then(|values| values.last())
-                    .map(|&(_, ref val)| val.end)
-                    .unwrap_or_else(|| header.1.len());
-                Ok((
-                    Value {
-                        e: E::DottedTable(table.values.unwrap_or_default()),
-                        start,
-                        end,
-                    },
-                    Some(header.1.clone()),
-                ))
-            }
-            Some(_) => self.value().map(|val| (val, None)),
-            None => Err(self.eof()),
-        }
-    }
-
-    fn number(&mut self, Span { start, end }: Span, s: &'a str) -> Result<Value<'a>, Error> {
-        let to_integer = |f| Value {
-            e: E::Integer(f),
-            start,
-            end,
-        };
-        if let Some(value) = s.strip_prefix("0x") {
-            self.integer(value, 16).map(to_integer)
-        } else if let Some(value) = s.strip_prefix("0o") {
-            self.integer(value, 8).map(to_integer)
-        } else if let Some(value) = s.strip_prefix("0b") {
-            self.integer(value, 2).map(to_integer)
-        } else if s.contains('e') || s.contains('E') {
-            self.float(s, None).map(|f| Value {
-                e: E::Float(f),
-                start,
-                end,
-            })
-        } else if self.eat(Token::Period)? {
-            let at = self.tokens.current();
-            match self.next()? {
-                Some((Span { start, end }, Token::Keylike(after))) => {
-                    self.float(s, Some(after)).map(|f| Value {
-                        e: E::Float(f),
-                        start,
-                        end,
-                    })
-                }
-                _ => Err(self.error(at, ErrorKind::NumberInvalid)),
-            }
-        } else if s == "inf" {
-            Ok(Value {
-                e: E::Float(f64::INFINITY),
-                start,
-                end,
-            })
-        } else if s == "-inf" {
-            Ok(Value {
-                e: E::Float(f64::NEG_INFINITY),
-                start,
-                end,
-            })
-        } else if s == "nan" {
-            Ok(Value {
-                e: E::Float(f64::NAN),
-                start,
-                end,
-            })
-        } else if s == "-nan" {
-            Ok(Value {
-                e: E::Float(-f64::NAN),
-                start,
-                end,
-            })
-        } else {
-            self.integer(s, 10).map(to_integer)
-        }
-    }
-
-    fn number_leading_plus(&mut self, Span { start, .. }: Span) -> Result<Value<'a>, Error> {
-        let start_token = self.tokens.current();
-        match self.next()? {
-            Some((Span { end, .. }, Token::Keylike(s))) => self.number(Span { start, end }, s),
-            _ => Err(self.error(start_token, ErrorKind::NumberInvalid)),
-        }
-    }
-
-    fn integer(&self, s: &'a str, radix: u32) -> Result<i64, Error> {
-        let allow_sign = radix == 10;
-        let allow_leading_zeros = radix != 10;
-        let (prefix, suffix) = self.parse_integer(s, allow_sign, allow_leading_zeros, radix)?;
-        let start = self.tokens.substr_offset(s);
-        if !suffix.is_empty() {
-            return Err(self.error(start, ErrorKind::NumberInvalid));
-        }
-        i64::from_str_radix(prefix.replace('_', "").trim_start_matches('+'), radix)
-            .map_err(|_e| self.error(start, ErrorKind::NumberInvalid))
-    }
-
-    fn parse_integer(
-        &self,
-        s: &'a str,
-        allow_sign: bool,
-        allow_leading_zeros: bool,
-        radix: u32,
-    ) -> Result<(&'a str, &'a str), Error> {
-        let start = self.tokens.substr_offset(s);
-
-        let mut first = true;
-        let mut first_zero = false;
-        let mut underscore = false;
-        let mut end = s.len();
-        for (i, c) in s.char_indices() {
-            let at = i + start;
-            if i == 0 && (c == '+' || c == '-') && allow_sign {
-                continue;
-            }
-
-            if c == '0' && first {
-                first_zero = true;
-            } else if c.is_digit(radix) {
-                if !first && first_zero && !allow_leading_zeros {
-                    return Err(self.error(at, ErrorKind::NumberInvalid));
-                }
-                underscore = false;
-            } else if c == '_' && first {
-                return Err(self.error(at, ErrorKind::NumberInvalid));
-            } else if c == '_' && !underscore {
-                underscore = true;
-            } else {
-                end = i;
-                break;
-            }
-            first = false;
-        }
-        if first || underscore {
-            return Err(self.error(start, ErrorKind::NumberInvalid));
-        }
-        Ok((&s[..end], &s[end..]))
-    }
-
-    fn float(&mut self, s: &'a str, after_decimal: Option<&'a str>) -> Result<f64, Error> {
-        let (integral, mut suffix) = self.parse_integer(s, true, false, 10)?;
-        let start = self.tokens.substr_offset(integral);
-
-        let mut fraction = None;
-        if let Some(after) = after_decimal {
-            if !suffix.is_empty() {
-                return Err(self.error(start, ErrorKind::NumberInvalid));
-            }
-            let (a, b) = self.parse_integer(after, false, true, 10)?;
-            fraction = Some(a);
-            suffix = b;
-        }
-
-        let mut exponent = None;
-        if suffix.starts_with('e') || suffix.starts_with('E') {
-            let (a, b) = if suffix.len() == 1 {
-                self.eat(Token::Plus)?;
-                match self.next()? {
-                    Some((_, Token::Keylike(s))) => self.parse_integer(s, false, true, 10)?,
-                    _ => return Err(self.error(start, ErrorKind::NumberInvalid)),
-                }
-            } else {
-                self.parse_integer(&suffix[1..], true, true, 10)?
-            };
-            if !b.is_empty() {
-                return Err(self.error(start, ErrorKind::NumberInvalid));
-            }
-            exponent = Some(a);
-        } else if !suffix.is_empty() {
-            return Err(self.error(start, ErrorKind::NumberInvalid));
-        }
-
-        let mut number = integral
-            .trim_start_matches('+')
-            .chars()
-            .filter(|c| *c != '_')
-            .collect::<String>();
-        if let Some(fraction) = fraction {
-            number.push('.');
-            number.extend(fraction.chars().filter(|c| *c != '_'));
-        }
-        if let Some(exponent) = exponent {
-            number.push('E');
-            number.extend(exponent.chars().filter(|c| *c != '_'));
-        }
-        number
-            .parse()
-            .map_err(|_e| self.error(start, ErrorKind::NumberInvalid))
-            .and_then(|n: f64| {
-                if n.is_finite() {
-                    Ok(n)
-                } else {
-                    Err(self.error(start, ErrorKind::NumberInvalid))
-                }
-            })
-    }
-
-    fn datetime(
-        &mut self,
-        mut span: Span,
-        date: &'a str,
-        colon_eaten: bool,
-    ) -> Result<(Span, &'a str), Error> {
-        let start = self.tokens.substr_offset(date);
-
-        // Check for space separated date and time.
-        let mut lookahead = self.tokens.clone();
-        if let Ok(Some((_, Token::Whitespace(" ")))) = lookahead.next() {
-            // Check if hour follows.
-            if let Ok(Some((_, Token::Keylike(_)))) = lookahead.next() {
-                self.next()?; // skip space
-                self.next()?; // skip keylike hour
-            }
-        }
-
-        if colon_eaten || self.eat(Token::Colon)? {
-            // minutes
-            match self.next()? {
-                Some((_, Token::Keylike(_))) => {}
-                _ => return Err(self.error(start, ErrorKind::DateInvalid)),
-            }
-            // Seconds
-            self.expect(Token::Colon)?;
-            match self.next()? {
-                Some((Span { end, .. }, Token::Keylike(_))) => {
-                    span.end = end;
-                }
-                _ => return Err(self.error(start, ErrorKind::DateInvalid)),
-            }
-            // Fractional seconds
-            if self.eat(Token::Period)? {
-                match self.next()? {
-                    Some((Span { end, .. }, Token::Keylike(_))) => {
-                        span.end = end;
-                    }
-                    _ => return Err(self.error(start, ErrorKind::DateInvalid)),
-                }
-            }
-
-            // offset
-            if self.eat(Token::Plus)? {
-                match self.next()? {
-                    Some((Span { end, .. }, Token::Keylike(_))) => {
-                        span.end = end;
-                    }
-                    _ => return Err(self.error(start, ErrorKind::DateInvalid)),
-                }
-            }
-            if self.eat(Token::Colon)? {
-                match self.next()? {
-                    Some((Span { end, .. }, Token::Keylike(_))) => {
-                        span.end = end;
-                    }
-                    _ => return Err(self.error(start, ErrorKind::DateInvalid)),
-                }
-            }
-        }
-
-        let end = self.tokens.current();
-        Ok((span, &self.tokens.input()[start..end]))
-    }
-
-    // TODO(#140): shouldn't buffer up this entire table in memory, it'd be
-    // great to defer parsing everything until later.
-    fn inline_table(&mut self) -> Result<(Span, Vec<TablePair<'a>>), Error> {
-        let mut ret = Vec::new();
-        self.eat_whitespace()?;
-        if let Some(span) = self.eat_spanned(Token::RightBrace)? {
-            return Ok((span, ret));
-        }
-        loop {
-            let key = self.dotted_key()?;
-            self.eat_whitespace()?;
-            self.expect(Token::Equals)?;
-            self.eat_whitespace()?;
-            let value = self.value()?;
-            self.add_dotted_key(key, value, &mut ret)?;
-
-            self.eat_whitespace()?;
-            if let Some(span) = self.eat_spanned(Token::RightBrace)? {
-                return Ok((span, ret));
-            }
-            self.expect(Token::Comma)?;
-            self.eat_whitespace()?;
-        }
-    }
-
-    // TODO(#140): shouldn't buffer up this entire array in memory, it'd be
-    // great to defer parsing everything until later.
-    fn array(&mut self) -> Result<(Span, Vec<Value<'a>>), Error> {
-        let mut ret = Vec::new();
-
-        let intermediate = |me: &mut Deserializer<'_>| {
-            loop {
-                me.eat_whitespace()?;
-                if !me.eat(Token::Newline)? && !me.eat_comment()? {
-                    break;
-                }
-            }
-            Ok(())
-        };
-
-        loop {
-            intermediate(self)?;
-            if let Some(span) = self.eat_spanned(Token::RightBracket)? {
-                return Ok((span, ret));
-            }
-            let value = self.value()?;
-            ret.push(value);
-            intermediate(self)?;
-            if !self.eat(Token::Comma)? {
-                break;
-            }
-        }
-        intermediate(self)?;
-        let span = self.expect_spanned(Token::RightBracket)?;
-        Ok((span, ret))
-    }
-
-    fn table_key(&mut self) -> Result<(Span, Cow<'a, str>), Error> {
-        self.tokens.table_key().map_err(|e| self.token_error(e))
-    }
-
-    fn dotted_key(&mut self) -> Result<Vec<(Span, Cow<'a, str>)>, Error> {
-        let mut result = vec![self.table_key()?];
-        self.eat_whitespace()?;
-        while self.eat(Token::Period)? {
-            self.eat_whitespace()?;
-            result.push(self.table_key()?);
-            self.eat_whitespace()?;
-        }
-        Ok(result)
-    }
-
-    /// Stores a value in the appropriate hierarchical structure positioned based on the dotted key.
-    ///
-    /// Given the following definition: `multi.part.key = "value"`, `multi` and `part` are
-    /// intermediate parts which are mapped to the relevant fields in the deserialized type's data
-    /// hierarchy.
-    ///
-    /// # Parameters
-    ///
-    /// * `key_parts`: Each segment of the dotted key, e.g. `part.one` maps to
-    ///                `vec![Cow::Borrowed("part"), Cow::Borrowed("one")].`
-    /// * `value`: The parsed value.
-    /// * `values`: The `Vec` to store the value in.
-    fn add_dotted_key(
-        &self,
-        mut key_parts: Vec<(Span, Cow<'a, str>)>,
-        value: Value<'a>,
-        values: &mut Vec<TablePair<'a>>,
-    ) -> Result<(), Error> {
-        let key = key_parts.remove(0);
-        if key_parts.is_empty() {
-            values.push((key, value));
-            return Ok(());
-        }
-        match values.iter_mut().find(|&&mut (ref k, _)| *k.1 == key.1) {
-            Some(&mut (
-                _,
-                Value {
-                    e: E::DottedTable(ref mut v),
-                    ..
-                },
-            )) => {
-                return self.add_dotted_key(key_parts, value, v);
-            }
-            Some(&mut (_, Value { start, .. })) => {
-                return Err(self.error(start, ErrorKind::DottedKeyInvalidType));
-            }
-            None => {}
-        }
-        // The start/end value is somewhat misleading here.
-        let table_values = Value {
-            e: E::DottedTable(Vec::new()),
-            start: value.start,
-            end: value.end,
-        };
-        values.push((key, table_values));
-        let last_i = values.len() - 1;
-        if let (
-            _,
-            Value {
-                e: E::DottedTable(ref mut v),
-                ..
-            },
-        ) = values[last_i]
-        {
-            self.add_dotted_key(key_parts, value, v)?;
-        }
-        Ok(())
-    }
-
-    fn eat_whitespace(&mut self) -> Result<(), Error> {
-        self.tokens
-            .eat_whitespace()
-            .map_err(|e| self.token_error(e))
-    }
-
-    fn eat_comment(&mut self) -> Result<bool, Error> {
-        self.tokens.eat_comment().map_err(|e| self.token_error(e))
-    }
-
-    fn eat_newline_or_eof(&mut self) -> Result<(), Error> {
-        self.tokens
-            .eat_newline_or_eof()
-            .map_err(|e| self.token_error(e))
-    }
-
-    fn eat(&mut self, expected: Token<'a>) -> Result<bool, Error> {
-        self.tokens.eat(expected).map_err(|e| self.token_error(e))
-    }
-
-    fn eat_spanned(&mut self, expected: Token<'a>) -> Result<Option<Span>, Error> {
-        self.tokens
-            .eat_spanned(expected)
-            .map_err(|e| self.token_error(e))
-    }
-
-    fn expect(&mut self, expected: Token<'a>) -> Result<(), Error> {
-        self.tokens
-            .expect(expected)
-            .map_err(|e| self.token_error(e))
-    }
-
-    fn expect_spanned(&mut self, expected: Token<'a>) -> Result<Span, Error> {
-        self.tokens
-            .expect_spanned(expected)
-            .map_err(|e| self.token_error(e))
-    }
-
-    fn next(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
-        self.tokens.next().map_err(|e| self.token_error(e))
-    }
-
-    fn peek(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
-        self.tokens.peek().map_err(|e| self.token_error(e))
-    }
-
-    fn eof(&self) -> Error {
-        self.error(self.input.len(), ErrorKind::UnexpectedEof)
-    }
-
-    fn token_error(&self, error: TokenError) -> Error {
-        match error {
-            TokenError::InvalidCharInString(at, ch) => {
-                self.error(at, ErrorKind::InvalidCharInString(ch))
-            }
-            TokenError::InvalidEscape(at, ch) => self.error(at, ErrorKind::InvalidEscape(ch)),
-            TokenError::InvalidEscapeValue(at, v) => {
-                self.error(at, ErrorKind::InvalidEscapeValue(v))
-            }
-            TokenError::InvalidHexEscape(at, ch) => self.error(at, ErrorKind::InvalidHexEscape(ch)),
-            TokenError::NewlineInString(at) => self.error(at, ErrorKind::NewlineInString),
-            TokenError::Unexpected(at, ch) => self.error(at, ErrorKind::Unexpected(ch)),
-            TokenError::UnterminatedString(at) => self.error(at, ErrorKind::UnterminatedString),
-            TokenError::NewlineInTableKey(at) => self.error(at, ErrorKind::NewlineInTableKey),
-            TokenError::Wanted {
-                at,
-                expected,
-                found,
-            } => self.error(at, ErrorKind::Wanted { expected, found }),
-            TokenError::MultilineStringKey(at) => self.error(at, ErrorKind::MultilineStringKey),
-        }
-    }
-
-    fn error(&self, at: usize, kind: ErrorKind) -> Error {
-        let mut err = Error::from_kind(Some(at), kind);
-        err.fix_linecol(|at| self.to_linecol(at));
-        err
-    }
-
-    /// Converts a byte offset from an error message to a (line, column) pair
-    ///
-    /// All indexes are 0-based.
-    fn to_linecol(&self, offset: usize) -> (usize, usize) {
-        let mut cur = 0;
-        // Use split_terminator instead of lines so that if there is a `\r`,
-        // it is included in the offset calculation. The `+1` values below
-        // account for the `\n`.
-        for (i, line) in self.input.split_terminator('\n').enumerate() {
-            if cur + line.len() + 1 > offset {
-                return (i, offset - cur);
-            }
-            cur += line.len() + 1;
-        }
-        (self.input.lines().count(), 0)
-    }
-}
-
-impl Error {
-    /// Produces a (line, column) pair of the position of the error if available
-    ///
-    /// All indexes are 0-based.
-    pub fn line_col(&self) -> Option<(usize, usize)> {
-        self.inner.line.map(|line| (line, self.inner.col))
-    }
-
-    fn from_kind(at: Option<usize>, kind: ErrorKind) -> Error {
-        Error {
-            inner: Box::new(ErrorInner {
-                kind,
-                line: None,
-                col: 0,
-                at,
-                message: String::new(),
-                key: Vec::new(),
-            }),
-        }
-    }
-
-    fn custom(at: Option<usize>, s: String) -> Error {
-        Error {
-            inner: Box::new(ErrorInner {
-                kind: ErrorKind::Custom,
-                line: None,
-                col: 0,
-                at,
-                message: s,
-                key: Vec::new(),
-            }),
-        }
-    }
-
-    pub(crate) fn add_key_context(&mut self, key: &str) {
-        self.inner.key.insert(0, key.to_string());
-    }
-
-    fn fix_offset<F>(&mut self, f: F)
-    where
-        F: FnOnce() -> Option<usize>,
-    {
-        // An existing offset is always better positioned than anything we
-        // might want to add later.
-        if self.inner.at.is_none() {
-            self.inner.at = f();
-        }
-    }
-
-    fn fix_linecol<F>(&mut self, f: F)
+    ) -> Result<V::Value, Error>
     where
-        F: FnOnce(usize) -> (usize, usize),
+        V: serde::de::Visitor<'de>,
     {
-        if let Some(at) = self.inner.at {
-            let (line, col) = f(at);
-            self.inner.line = Some(line);
-            self.inner.col = col;
-        }
-    }
-}
-
-impl std::convert::From<Error> for std::io::Error {
-    fn from(e: Error) -> Self {
-        std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match &self.inner.kind {
-            ErrorKind::UnexpectedEof => "unexpected eof encountered".fmt(f)?,
-            ErrorKind::InvalidCharInString(c) => write!(
-                f,
-                "invalid character in string: `{}`",
-                c.escape_default().collect::<String>()
-            )?,
-            ErrorKind::InvalidEscape(c) => write!(
-                f,
-                "invalid escape character in string: `{}`",
-                c.escape_default().collect::<String>()
-            )?,
-            ErrorKind::InvalidHexEscape(c) => write!(
-                f,
-                "invalid hex escape character in string: `{}`",
-                c.escape_default().collect::<String>()
-            )?,
-            ErrorKind::InvalidEscapeValue(c) => write!(f, "invalid escape value: `{}`", c)?,
-            ErrorKind::NewlineInString => "newline in string found".fmt(f)?,
-            ErrorKind::Unexpected(ch) => write!(
-                f,
-                "unexpected character found: `{}`",
-                ch.escape_default().collect::<String>()
-            )?,
-            ErrorKind::UnterminatedString => "unterminated string".fmt(f)?,
-            ErrorKind::NewlineInTableKey => "found newline in table key".fmt(f)?,
-            ErrorKind::Wanted { expected, found } => {
-                write!(f, "expected {}, found {}", expected, found)?
-            }
-            ErrorKind::NumberInvalid => "invalid number".fmt(f)?,
-            ErrorKind::DateInvalid => "invalid date".fmt(f)?,
-            ErrorKind::DuplicateTable(ref s) => {
-                write!(f, "redefinition of table `{}`", s)?;
-            }
-            ErrorKind::RedefineAsArray => "table redefined as array".fmt(f)?,
-            ErrorKind::EmptyTableKey => "empty table key found".fmt(f)?,
-            ErrorKind::MultilineStringKey => "multiline strings are not allowed for key".fmt(f)?,
-            ErrorKind::Custom => self.inner.message.fmt(f)?,
-            ErrorKind::ExpectedTuple(l) => write!(f, "expected table with length {}", l)?,
-            ErrorKind::ExpectedTupleIndex {
-                expected,
-                ref found,
-            } => write!(f, "expected table key `{}`, but was `{}`", expected, found)?,
-            ErrorKind::ExpectedEmptyTable => "expected empty table".fmt(f)?,
-            ErrorKind::DottedKeyInvalidType => {
-                "dotted key attempted to extend non-table type".fmt(f)?
-            }
-            ErrorKind::UnexpectedKeys {
-                ref keys,
-                available,
-            } => write!(
-                f,
-                "unexpected keys in table: `{:?}`, available keys: `{:?}`",
-                keys, available
-            )?,
-            ErrorKind::UnquotedString => write!(
-                f,
-                "invalid TOML value, did you mean to use a quoted string?"
-            )?,
-        }
-
-        if !self.inner.key.is_empty() {
-            write!(f, " for key `")?;
-            for (i, k) in self.inner.key.iter().enumerate() {
-                if i > 0 {
-                    write!(f, ".")?;
-                }
-                write!(f, "{}", k)?;
-            }
-            write!(f, "`")?;
-        }
-
-        if let Some(line) = self.inner.line {
-            write!(f, " at line {} column {}", line + 1, self.inner.col + 1)?;
-        }
-
-        Ok(())
-    }
-}
-
-impl error::Error for Error {}
-
-impl de::Error for Error {
-    fn custom<T: fmt::Display>(msg: T) -> Error {
-        Error::custom(None, msg.to_string())
+        let inner = self
+            .input
+            .parse::<toml_edit::de::ValueDeserializer>()
+            .map_err(Error::new)?;
+        inner
+            .deserialize_enum(name, variants, visitor)
+            .map_err(Error::new)
     }
-}
-
-enum Line<'a> {
-    Table {
-        at: usize,
-        header: Header<'a>,
-        array: bool,
-    },
-    KeyValue(Vec<(Span, Cow<'a, str>)>, Value<'a>),
-}
-
-struct Header<'a> {
-    first: bool,
-    array: bool,
-    require_newline_after_table: bool,
-    tokens: Tokenizer<'a>,
-}
 
-impl<'a> Header<'a> {
-    fn new(tokens: Tokenizer<'a>, array: bool, require_newline_after_table: bool) -> Header<'a> {
-        Header {
-            first: true,
-            array,
-            tokens,
-            require_newline_after_table,
-        }
-    }
-
-    fn next(&mut self) -> Result<Option<(Span, Cow<'a, str>)>, TokenError> {
-        self.tokens.eat_whitespace()?;
-
-        if self.first || self.tokens.eat(Token::Period)? {
-            self.first = false;
-            self.tokens.eat_whitespace()?;
-            self.tokens.table_key().map(Some)
-        } else {
-            self.tokens.expect(Token::RightBracket)?;
-            if self.array {
-                self.tokens.expect(Token::RightBracket)?;
-            }
-
-            self.tokens.eat_whitespace()?;
-            if self.require_newline_after_table && !self.tokens.eat_comment()? {
-                self.tokens.eat_newline_or_eof()?;
-            }
-            Ok(None)
-        }
-    }
-}
-
-#[derive(Debug)]
-struct Value<'a> {
-    e: E<'a>,
-    start: usize,
-    end: usize,
-}
-
-#[derive(Debug)]
-enum E<'a> {
-    Integer(i64),
-    Float(f64),
-    Boolean(bool),
-    String(Cow<'a, str>),
-    Datetime(&'a str),
-    Array(Vec<Value<'a>>),
-    InlineTable(Vec<TablePair<'a>>),
-    DottedTable(Vec<TablePair<'a>>),
-}
-
-impl<'a> E<'a> {
-    fn type_name(&self) -> &'static str {
-        match *self {
-            E::String(..) => "string",
-            E::Integer(..) => "integer",
-            E::Float(..) => "float",
-            E::Boolean(..) => "boolean",
-            E::Datetime(..) => "datetime",
-            E::Array(..) => "array",
-            E::InlineTable(..) => "inline table",
-            E::DottedTable(..) => "dotted table",
-        }
+    serde::forward_to_deserialize_any! {
+        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+        bytes byte_buf map unit
+        ignored_any unit_struct tuple_struct tuple identifier
     }
 }
diff --git a/crates/toml/src/lib.rs b/crates/toml/src/lib.rs
index 4dd87fd9..13cf5387 100644
--- a/crates/toml/src/lib.rs
+++ b/crates/toml/src/lib.rs
@@ -155,8 +155,7 @@ pub mod ser;
 pub use crate::ser::{to_string, to_string_pretty, to_vec, Serializer};
 pub mod de;
 #[doc(no_inline)]
-pub use crate::de::{from_slice, from_str, Deserializer};
-mod tokens;
+pub use crate::de::{from_str, Deserializer, ValueDeserializer};
 
 #[doc(hidden)]
 pub mod macros;
diff --git a/crates/toml/src/ser.rs b/crates/toml/src/ser.rs
index efe8116a..74bacb6b 100644
--- a/crates/toml/src/ser.rs
+++ b/crates/toml/src/ser.rs
@@ -1140,7 +1140,7 @@ impl<'a, 'b> ser::SerializeStruct for SerializeTable<'a, 'b> {
         match *self {
             SerializeTable::Datetime(ref mut ser) => {
                 if key == datetime::FIELD {
-                    value.serialize(DateStrEmitter(*ser))?;
+                    value.serialize(DateStrEmitter(ser))?;
                 } else {
                     return Err(Error::DateInvalid);
                 }
diff --git a/crates/toml/src/tokens.rs b/crates/toml/src/tokens.rs
deleted file mode 100644
index ea1e7ebd..00000000
--- a/crates/toml/src/tokens.rs
+++ /dev/null
@@ -1,742 +0,0 @@
-use std::borrow::Cow;
-use std::char;
-use std::str;
-use std::string;
-use std::string::String as StdString;
-
-use self::Token::*;
-
-/// A span, designating a range of bytes where a token is located.
-#[derive(Eq, PartialEq, Debug, Clone, Copy)]
-pub struct Span {
-    /// The start of the range.
-    pub start: usize,
-    /// The end of the range (exclusive).
-    pub end: usize,
-}
-
-impl From<Span> for (usize, usize) {
-    fn from(Span { start, end }: Span) -> (usize, usize) {
-        (start, end)
-    }
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub enum Token<'a> {
-    Whitespace(&'a str),
-    Newline,
-    Comment(&'a str),
-
-    Equals,
-    Period,
-    Comma,
-    Colon,
-    Plus,
-    LeftBrace,
-    RightBrace,
-    LeftBracket,
-    RightBracket,
-
-    Keylike(&'a str),
-    String {
-        src: &'a str,
-        val: Cow<'a, str>,
-        multiline: bool,
-    },
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub enum Error {
-    InvalidCharInString(usize, char),
-    InvalidEscape(usize, char),
-    InvalidHexEscape(usize, char),
-    InvalidEscapeValue(usize, u32),
-    NewlineInString(usize),
-    Unexpected(usize, char),
-    UnterminatedString(usize),
-    NewlineInTableKey(usize),
-    MultilineStringKey(usize),
-    Wanted {
-        at: usize,
-        expected: &'static str,
-        found: &'static str,
-    },
-}
-
-#[derive(Clone)]
-pub struct Tokenizer<'a> {
-    input: &'a str,
-    chars: CrlfFold<'a>,
-}
-
-#[derive(Clone)]
-struct CrlfFold<'a> {
-    chars: str::CharIndices<'a>,
-}
-
-#[derive(Debug)]
-enum MaybeString {
-    NotEscaped(usize),
-    Owned(string::String),
-}
-
-impl<'a> Tokenizer<'a> {
-    pub fn new(input: &'a str) -> Tokenizer<'a> {
-        let mut t = Tokenizer {
-            input,
-            chars: CrlfFold {
-                chars: input.char_indices(),
-            },
-        };
-        // Eat utf-8 BOM
-        t.eatc('\u{feff}');
-        t
-    }
-
-    pub fn next(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
-        let (start, token) = match self.one() {
-            Some((start, '\n')) => (start, Newline),
-            Some((start, ' ')) => (start, self.whitespace_token(start)),
-            Some((start, '\t')) => (start, self.whitespace_token(start)),
-            Some((start, '#')) => (start, self.comment_token(start)),
-            Some((start, '=')) => (start, Equals),
-            Some((start, '.')) => (start, Period),
-            Some((start, ',')) => (start, Comma),
-            Some((start, ':')) => (start, Colon),
-            Some((start, '+')) => (start, Plus),
-            Some((start, '{')) => (start, LeftBrace),
-            Some((start, '}')) => (start, RightBrace),
-            Some((start, '[')) => (start, LeftBracket),
-            Some((start, ']')) => (start, RightBracket),
-            Some((start, '\'')) => {
-                return self
-                    .literal_string(start)
-                    .map(|t| Some((self.step_span(start), t)))
-            }
-            Some((start, '"')) => {
-                return self
-                    .basic_string(start)
-                    .map(|t| Some((self.step_span(start), t)))
-            }
-            Some((start, ch)) if is_keylike(ch) => (start, self.keylike(start)),
-
-            Some((start, ch)) => return Err(Error::Unexpected(start, ch)),
-            None => return Ok(None),
-        };
-
-        let span = self.step_span(start);
-        Ok(Some((span, token)))
-    }
-
-    pub fn peek(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
-        self.clone().next()
-    }
-
-    pub fn eat(&mut self, expected: Token<'a>) -> Result<bool, Error> {
-        self.eat_spanned(expected).map(|s| s.is_some())
-    }
-
-    /// Eat a value, returning it's span if it was consumed.
-    pub fn eat_spanned(&mut self, expected: Token<'a>) -> Result<Option<Span>, Error> {
-        let span = match self.peek()? {
-            Some((span, ref found)) if expected == *found => span,
-            Some(_) => return Ok(None),
-            None => return Ok(None),
-        };
-
-        drop(self.next());
-        Ok(Some(span))
-    }
-
-    pub fn expect(&mut self, expected: Token<'a>) -> Result<(), Error> {
-        // ignore span
-        let _ = self.expect_spanned(expected)?;
-        Ok(())
-    }
-
-    /// Expect the given token returning its span.
-    pub fn expect_spanned(&mut self, expected: Token<'a>) -> Result<Span, Error> {
-        let current = self.current();
-        match self.next()? {
-            Some((span, found)) => {
-                if expected == found {
-                    Ok(span)
-                } else {
-                    Err(Error::Wanted {
-                        at: current,
-                        expected: expected.describe(),
-                        found: found.describe(),
-                    })
-                }
-            }
-            None => Err(Error::Wanted {
-                at: self.input.len(),
-                expected: expected.describe(),
-                found: "eof",
-            }),
-        }
-    }
-
-    pub fn table_key(&mut self) -> Result<(Span, Cow<'a, str>), Error> {
-        let current = self.current();
-        match self.next()? {
-            Some((span, Token::Keylike(k))) => Ok((span, k.into())),
-            Some((
-                span,
-                Token::String {
-                    src,
-                    val,
-                    multiline,
-                },
-            )) => {
-                let offset = self.substr_offset(src);
-                if multiline {
-                    return Err(Error::MultilineStringKey(offset));
-                }
-                match src.find('\n') {
-                    None => Ok((span, val)),
-                    Some(i) => Err(Error::NewlineInTableKey(offset + i)),
-                }
-            }
-            Some((_, other)) => Err(Error::Wanted {
-                at: current,
-                expected: "a table key",
-                found: other.describe(),
-            }),
-            None => Err(Error::Wanted {
-                at: self.input.len(),
-                expected: "a table key",
-                found: "eof",
-            }),
-        }
-    }
-
-    pub fn eat_whitespace(&mut self) -> Result<(), Error> {
-        while self.eatc(' ') || self.eatc('\t') {
-            // ...
-        }
-        Ok(())
-    }
-
-    pub fn eat_comment(&mut self) -> Result<bool, Error> {
-        if !self.eatc('#') {
-            return Ok(false);
-        }
-        drop(self.comment_token(0));
-        self.eat_newline_or_eof().map(|()| true)
-    }
-
-    pub fn eat_newline_or_eof(&mut self) -> Result<(), Error> {
-        let current = self.current();
-        match self.next()? {
-            None | Some((_, Token::Newline)) => Ok(()),
-            Some((_, other)) => Err(Error::Wanted {
-                at: current,
-                expected: "newline",
-                found: other.describe(),
-            }),
-        }
-    }
-
-    pub fn skip_to_newline(&mut self) {
-        loop {
-            match self.one() {
-                Some((_, '\n')) | None => break,
-                _ => {}
-            }
-        }
-    }
-
-    fn eatc(&mut self, ch: char) -> bool {
-        match self.chars.clone().next() {
-            Some((_, ch2)) if ch == ch2 => {
-                self.one();
-                true
-            }
-            _ => false,
-        }
-    }
-
-    pub fn current(&mut self) -> usize {
-        self.chars
-            .clone()
-            .next()
-            .map(|i| i.0)
-            .unwrap_or_else(|| self.input.len())
-    }
-
-    pub fn input(&self) -> &'a str {
-        self.input
-    }
-
-    fn whitespace_token(&mut self, start: usize) -> Token<'a> {
-        while self.eatc(' ') || self.eatc('\t') {
-            // ...
-        }
-        Whitespace(&self.input[start..self.current()])
-    }
-
-    fn comment_token(&mut self, start: usize) -> Token<'a> {
-        while let Some((_, ch)) = self.chars.clone().next() {
-            if ch != '\t' && !('\u{20}'..='\u{10ffff}').contains(&ch) {
-                break;
-            }
-            self.one();
-        }
-        Comment(&self.input[start..self.current()])
-    }
-
-    #[allow(clippy::type_complexity)]
-    fn read_string(
-        &mut self,
-        delim: char,
-        start: usize,
-        new_ch: &mut dyn FnMut(
-            &mut Tokenizer<'_>,
-            &mut MaybeString,
-            bool,
-            usize,
-            char,
-        ) -> Result<(), Error>,
-    ) -> Result<Token<'a>, Error> {
-        let mut multiline = false;
-        if self.eatc(delim) {
-            if self.eatc(delim) {
-                multiline = true;
-            } else {
-                return Ok(String {
-                    src: &self.input[start..start + 2],
-                    val: Cow::Borrowed(""),
-                    multiline: false,
-                });
-            }
-        }
-        let mut val = MaybeString::NotEscaped(self.current());
-        let mut n = 0;
-        'outer: loop {
-            n += 1;
-            match self.one() {
-                Some((i, '\n')) => {
-                    if multiline {
-                        if self.input.as_bytes()[i] == b'\r' {
-                            val.to_owned(&self.input[..i]);
-                        }
-                        if n == 1 {
-                            val = MaybeString::NotEscaped(self.current());
-                        } else {
-                            val.push('\n');
-                        }
-                        continue;
-                    } else {
-                        return Err(Error::NewlineInString(i));
-                    }
-                }
-                Some((mut i, ch)) if ch == delim => {
-                    if multiline {
-                        if !self.eatc(delim) {
-                            val.push(delim);
-                            continue 'outer;
-                        }
-                        if !self.eatc(delim) {
-                            val.push(delim);
-                            val.push(delim);
-                            continue 'outer;
-                        }
-                        if self.eatc(delim) {
-                            val.push(delim);
-                            i += 1;
-                        }
-                        if self.eatc(delim) {
-                            val.push(delim);
-                            i += 1;
-                        }
-                    }
-                    return Ok(String {
-                        src: &self.input[start..self.current()],
-                        val: val.into_cow(&self.input[..i]),
-                        multiline,
-                    });
-                }
-                Some((i, c)) => new_ch(self, &mut val, multiline, i, c)?,
-                None => return Err(Error::UnterminatedString(start)),
-            }
-        }
-    }
-
-    fn literal_string(&mut self, start: usize) -> Result<Token<'a>, Error> {
-        self.read_string('\'', start, &mut |_me, val, _multi, i, ch| {
-            if ch == '\u{09}' || (('\u{20}'..='\u{10ffff}').contains(&ch) && ch != '\u{7f}') {
-                val.push(ch);
-                Ok(())
-            } else {
-                Err(Error::InvalidCharInString(i, ch))
-            }
-        })
-    }
-
-    fn basic_string(&mut self, start: usize) -> Result<Token<'a>, Error> {
-        self.read_string('"', start, &mut |me, val, multi, i, ch| match ch {
-            '\\' => {
-                val.to_owned(&me.input[..i]);
-                match me.chars.next() {
-                    Some((_, '"')) => val.push('"'),
-                    Some((_, '\\')) => val.push('\\'),
-                    Some((_, 'b')) => val.push('\u{8}'),
-                    Some((_, 'f')) => val.push('\u{c}'),
-                    Some((_, 'n')) => val.push('\n'),
-                    Some((_, 'r')) => val.push('\r'),
-                    Some((_, 't')) => val.push('\t'),
-                    Some((i, c @ 'u')) | Some((i, c @ 'U')) => {
-                        let len = if c == 'u' { 4 } else { 8 };
-                        val.push(me.hex(start, i, len)?);
-                    }
-                    Some((i, c @ ' ')) | Some((i, c @ '\t')) | Some((i, c @ '\n')) if multi => {
-                        if c != '\n' {
-                            while let Some((_, ch)) = me.chars.clone().next() {
-                                match ch {
-                                    ' ' | '\t' => {
-                                        me.chars.next();
-                                        continue;
-                                    }
-                                    '\n' => {
-                                        me.chars.next();
-                                        break;
-                                    }
-                                    _ => return Err(Error::InvalidEscape(i, c)),
-                                }
-                            }
-                        }
-                        while let Some((_, ch)) = me.chars.clone().next() {
-                            match ch {
-                                ' ' | '\t' | '\n' => {
-                                    me.chars.next();
-                                }
-                                _ => break,
-                            }
-                        }
-                    }
-                    Some((i, c)) => return Err(Error::InvalidEscape(i, c)),
-                    None => return Err(Error::UnterminatedString(start)),
-                }
-                Ok(())
-            }
-            ch if ch == '\u{09}' || (('\u{20}'..='\u{10ffff}').contains(&ch) && ch != '\u{7f}') => {
-                val.push(ch);
-                Ok(())
-            }
-            _ => Err(Error::InvalidCharInString(i, ch)),
-        })
-    }
-
-    fn hex(&mut self, start: usize, i: usize, len: usize) -> Result<char, Error> {
-        let mut buf = StdString::with_capacity(len);
-        for _ in 0..len {
-            match self.one() {
-                Some((_, ch)) if ch as u32 <= 0x7F && ch.is_ascii_hexdigit() => buf.push(ch),
-                Some((i, ch)) => return Err(Error::InvalidHexEscape(i, ch)),
-                None => return Err(Error::UnterminatedString(start)),
-            }
-        }
-        let val = u32::from_str_radix(&buf, 16).unwrap();
-        match char::from_u32(val) {
-            Some(ch) => Ok(ch),
-            None => Err(Error::InvalidEscapeValue(i, val)),
-        }
-    }
-
-    fn keylike(&mut self, start: usize) -> Token<'a> {
-        while let Some((_, ch)) = self.peek_one() {
-            if !is_keylike(ch) {
-                break;
-            }
-            self.one();
-        }
-        Keylike(&self.input[start..self.current()])
-    }
-
-    pub fn substr_offset(&self, s: &'a str) -> usize {
-        assert!(s.len() <= self.input.len());
-        let a = self.input.as_ptr() as usize;
-        let b = s.as_ptr() as usize;
-        assert!(a <= b);
-        b - a
-    }
-
-    /// Calculate the span of a single character.
-    fn step_span(&mut self, start: usize) -> Span {
-        let end = self
-            .peek_one()
-            .map(|t| t.0)
-            .unwrap_or_else(|| self.input.len());
-        Span { start, end }
-    }
-
-    /// Peek one char without consuming it.
-    fn peek_one(&mut self) -> Option<(usize, char)> {
-        self.chars.clone().next()
-    }
-
-    /// Take one char.
-    pub fn one(&mut self) -> Option<(usize, char)> {
-        self.chars.next()
-    }
-}
-
-impl<'a> Iterator for CrlfFold<'a> {
-    type Item = (usize, char);
-
-    fn next(&mut self) -> Option<(usize, char)> {
-        self.chars.next().map(|(i, c)| {
-            if c == '\r' {
-                let mut attempt = self.chars.clone();
-                if let Some((_, '\n')) = attempt.next() {
-                    self.chars = attempt;
-                    return (i, '\n');
-                }
-            }
-            (i, c)
-        })
-    }
-}
-
-impl MaybeString {
-    fn push(&mut self, ch: char) {
-        match *self {
-            MaybeString::NotEscaped(..) => {}
-            MaybeString::Owned(ref mut s) => s.push(ch),
-        }
-    }
-
-    #[allow(clippy::wrong_self_convention)]
-    fn to_owned(&mut self, input: &str) {
-        match *self {
-            MaybeString::NotEscaped(start) => {
-                *self = MaybeString::Owned(input[start..].to_owned());
-            }
-            MaybeString::Owned(..) => {}
-        }
-    }
-
-    fn into_cow(self, input: &str) -> Cow<'_, str> {
-        match self {
-            MaybeString::NotEscaped(start) => Cow::Borrowed(&input[start..]),
-            MaybeString::Owned(s) => Cow::Owned(s),
-        }
-    }
-}
-
-fn is_keylike(ch: char) -> bool {
-    ('A'..='Z').contains(&ch)
-        || ('a'..='z').contains(&ch)
-        || ('0'..='9').contains(&ch)
-        || ch == '-'
-        || ch == '_'
-}
-
-impl<'a> Token<'a> {
-    pub fn describe(&self) -> &'static str {
-        match *self {
-            Token::Keylike(_) => "an identifier",
-            Token::Equals => "an equals",
-            Token::Period => "a period",
-            Token::Comment(_) => "a comment",
-            Token::Newline => "a newline",
-            Token::Whitespace(_) => "whitespace",
-            Token::Comma => "a comma",
-            Token::RightBrace => "a right brace",
-            Token::LeftBrace => "a left brace",
-            Token::RightBracket => "a right bracket",
-            Token::LeftBracket => "a left bracket",
-            Token::String { multiline, .. } => {
-                if multiline {
-                    "a multiline string"
-                } else {
-                    "a string"
-                }
-            }
-            Token::Colon => "a colon",
-            Token::Plus => "a plus",
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{Error, Token, Tokenizer};
-    use std::borrow::Cow;
-
-    fn err(input: &str, err: Error) {
-        let mut t = Tokenizer::new(input);
-        let token = t.next().unwrap_err();
-        assert_eq!(token, err);
-        assert!(t.next().unwrap().is_none());
-    }
-
-    #[test]
-    fn literal_strings() {
-        fn t(input: &str, val: &str, multiline: bool) {
-            let mut t = Tokenizer::new(input);
-            let (_, token) = t.next().unwrap().unwrap();
-            assert_eq!(
-                token,
-                Token::String {
-                    src: input,
-                    val: Cow::Borrowed(val),
-                    multiline,
-                }
-            );
-            assert!(t.next().unwrap().is_none());
-        }
-
-        t("''", "", false);
-        t("''''''", "", true);
-        t("'''\n'''", "", true);
-        t("'a'", "a", false);
-        t("'\"a'", "\"a", false);
-        t("''''a'''", "'a", true);
-        t("'''\n'a\n'''", "'a\n", true);
-        t("'''a\n'a\r\n'''", "a\n'a\n", true);
-    }
-
-    #[test]
-    fn basic_strings() {
-        fn t(input: &str, val: &str, multiline: bool) {
-            let mut t = Tokenizer::new(input);
-            let (_, token) = t.next().unwrap().unwrap();
-            assert_eq!(
-                token,
-                Token::String {
-                    src: input,
-                    val: Cow::Borrowed(val),
-                    multiline,
-                }
-            );
-            assert!(t.next().unwrap().is_none());
-        }
-
-        t(r#""""#, "", false);
-        t(r#""""""""#, "", true);
-        t(r#""a""#, "a", false);
-        t(r#""""a""""#, "a", true);
-        t(r#""\t""#, "\t", false);
-        t(r#""\u0000""#, "\0", false);
-        t(r#""\U00000000""#, "\0", false);
-        t(r#""\U000A0000""#, "\u{A0000}", false);
-        t(r#""\\t""#, "\\t", false);
-        t("\"\t\"", "\t", false);
-        t("\"\"\"\n\t\"\"\"", "\t", true);
-        t("\"\"\"\\\n\"\"\"", "", true);
-        t(
-            "\"\"\"\\\n     \t   \t  \\\r\n  \t \n  \t \r\n\"\"\"",
-            "",
-            true,
-        );
-        t(r#""\r""#, "\r", false);
-        t(r#""\n""#, "\n", false);
-        t(r#""\b""#, "\u{8}", false);
-        t(r#""a\fa""#, "a\u{c}a", false);
-        t(r#""\"a""#, "\"a", false);
-        t("\"\"\"\na\"\"\"", "a", true);
-        t("\"\"\"\n\"\"\"", "", true);
-        t(r#""""a\"""b""""#, "a\"\"\"b", true);
-        err(r#""\a"#, Error::InvalidEscape(2, 'a'));
-        err("\"\\\n", Error::InvalidEscape(2, '\n'));
-        err("\"\\\r\n", Error::InvalidEscape(2, '\n'));
-        err("\"\\", Error::UnterminatedString(0));
-        err("\"\u{0}", Error::InvalidCharInString(1, '\u{0}'));
-        err(r#""\U00""#, Error::InvalidHexEscape(5, '"'));
-        err(r#""\U00"#, Error::UnterminatedString(0));
-        err(r#""\uD800"#, Error::InvalidEscapeValue(2, 0xd800));
-        err(r#""\UFFFFFFFF"#, Error::InvalidEscapeValue(2, 0xffff_ffff));
-    }
-
-    #[test]
-    fn keylike() {
-        fn t(input: &str) {
-            let mut t = Tokenizer::new(input);
-            let (_, token) = t.next().unwrap().unwrap();
-            assert_eq!(token, Token::Keylike(input));
-            assert!(t.next().unwrap().is_none());
-        }
-        t("foo");
-        t("0bar");
-        t("bar0");
-        t("1234");
-        t("a-b");
-        t("a_B");
-        t("-_-");
-        t("___");
-    }
-
-    #[test]
-    fn all() {
-        fn t(input: &str, expected: &[((usize, usize), Token<'_>, &str)]) {
-            let mut tokens = Tokenizer::new(input);
-            let mut actual: Vec<((usize, usize), Token<'_>, &str)> = Vec::new();
-            while let Some((span, token)) = tokens.next().unwrap() {
-                actual.push((span.into(), token, &input[span.start..span.end]));
-            }
-            for (a, b) in actual.iter().zip(expected) {
-                assert_eq!(a, b);
-            }
-            assert_eq!(actual.len(), expected.len());
-        }
-
-        t(
-            " a ",
-            &[
-                ((0, 1), Token::Whitespace(" "), " "),
-                ((1, 2), Token::Keylike("a"), "a"),
-                ((2, 3), Token::Whitespace(" "), " "),
-            ],
-        );
-
-        t(
-            " a\t [[]] \t [] {} , . =\n# foo \r\n#foo \n ",
-            &[
-                ((0, 1), Token::Whitespace(" "), " "),
-                ((1, 2), Token::Keylike("a"), "a"),
-                ((2, 4), Token::Whitespace("\t "), "\t "),
-                ((4, 5), Token::LeftBracket, "["),
-                ((5, 6), Token::LeftBracket, "["),
-                ((6, 7), Token::RightBracket, "]"),
-                ((7, 8), Token::RightBracket, "]"),
-                ((8, 11), Token::Whitespace(" \t "), " \t "),
-                ((11, 12), Token::LeftBracket, "["),
-                ((12, 13), Token::RightBracket, "]"),
-                ((13, 14), Token::Whitespace(" "), " "),
-                ((14, 15), Token::LeftBrace, "{"),
-                ((15, 16), Token::RightBrace, "}"),
-                ((16, 17), Token::Whitespace(" "), " "),
-                ((17, 18), Token::Comma, ","),
-                ((18, 19), Token::Whitespace(" "), " "),
-                ((19, 20), Token::Period, "."),
-                ((20, 21), Token::Whitespace(" "), " "),
-                ((21, 22), Token::Equals, "="),
-                ((22, 23), Token::Newline, "\n"),
-                ((23, 29), Token::Comment("# foo "), "# foo "),
-                ((29, 31), Token::Newline, "\r\n"),
-                ((31, 36), Token::Comment("#foo "), "#foo "),
-                ((36, 37), Token::Newline, "\n"),
-                ((37, 38), Token::Whitespace(" "), " "),
-            ],
-        );
-    }
-
-    #[test]
-    fn bare_cr_bad() {
-        err("\r", Error::Unexpected(0, '\r'));
-        err("'\n", Error::NewlineInString(1));
-        err("'\u{0}", Error::InvalidCharInString(1, '\u{0}'));
-        err("'", Error::UnterminatedString(0));
-        err("\u{0}", Error::Unexpected(0, '\u{0}'));
-    }
-
-    #[test]
-    fn bad_comment() {
-        let mut t = Tokenizer::new("#\u{0}");
-        t.next().unwrap().unwrap();
-        assert_eq!(t.next(), Err(Error::Unexpected(1, '\u{0}')));
-        assert!(t.next().unwrap().is_none());
-    }
-}
diff --git a/crates/toml/src/value.rs b/crates/toml/src/value.rs
index 6e4dbc94..9f904dc1 100644
--- a/crates/toml/src/value.rs
+++ b/crates/toml/src/value.rs
@@ -693,14 +693,11 @@ impl<'de> de::MapAccess<'de> for MapDeserializer {
     where
         T: de::DeserializeSeed<'de>,
     {
-        let (key, res) = match self.value.take() {
+        let (_key, res) = match self.value.take() {
             Some((key, value)) => (key, seed.deserialize(value)),
             None => return Err(de::Error::custom("value is missing")),
         };
-        res.map_err(|mut error| {
-            error.add_key_context(&key);
-            error
-        })
+        res
     }
 
     fn size_hint(&self) -> Option<usize> {
diff --git a/crates/toml_edit/src/de/mod.rs b/crates/toml_edit/src/de/mod.rs
index b4b4b2e8..71d3f974 100644
--- a/crates/toml_edit/src/de/mod.rs
+++ b/crates/toml_edit/src/de/mod.rs
@@ -136,6 +136,8 @@ impl std::str::FromStr for Deserializer {
     }
 }
 
+// Note: this is wrapped by `toml::de::Deserializer` and any trait methods
+// implemented here need to be wrapped there
 impl<'de> serde::Deserializer<'de> for Deserializer {
     type Error = Error;
 
diff --git a/crates/toml_edit/src/de/value.rs b/crates/toml_edit/src/de/value.rs
index 5f553b97..ad2b40b5 100644
--- a/crates/toml_edit/src/de/value.rs
+++ b/crates/toml_edit/src/de/value.rs
@@ -23,6 +23,8 @@ impl ValueDeserializer {
     }
 }
 
+// Note: this is wrapped by `toml::de::ValueDeserializer` and any trait methods
+// implemented here need to be wrapped there
 impl<'de> serde::Deserializer<'de> for ValueDeserializer {
     type Error = Error;
 


Test patch:
diff --git a/crates/toml/tests/testsuite/backcompat.rs b/crates/toml/tests/testsuite/backcompat.rs
deleted file mode 100644
index d169069e..00000000
--- a/crates/toml/tests/testsuite/backcompat.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use serde::de::Deserialize;
-
-macro_rules! bad {
-    ($toml:expr, $msg:expr) => {
-        match $toml.parse::<toml::Value>() {
-            Ok(s) => panic!("parsed to: {:#?}", s),
-            Err(e) => assert_eq!(e.to_string(), $msg),
-        }
-    };
-}
-
-#[test]
-fn newlines_after_tables() {
-    let s = "
-        [a] foo = 1
-        [[b]] foo = 1
-    ";
-    bad!(
-        s,
-        "expected newline, found an identifier at line 2 column 13"
-    );
-
-    let mut d = toml::de::Deserializer::new(s);
-    d.set_require_newline_after_table(false);
-    let value = toml::Value::deserialize(&mut d).unwrap();
-    assert_eq!(value["a"]["foo"].as_integer(), Some(1));
-    assert_eq!(value["b"][0]["foo"].as_integer(), Some(1));
-}
-
-#[test]
-fn allow_duplicate_after_longer() {
-    let s = "
-        [dependencies.openssl-sys]
-        version = 1
-
-        [dependencies]
-        libc = 1
-
-        [dependencies]
-        bitflags = 1
-    ";
-    bad!(
-        s,
-        "redefinition of table `dependencies` for key `dependencies` at line 8 column 9"
-    );
-
-    let mut d = toml::de::Deserializer::new(s);
-    d.set_allow_duplicate_after_longer_table(true);
-    let value = toml::Value::deserialize(&mut d).unwrap();
-    assert_eq!(
-        value["dependencies"]["openssl-sys"]["version"].as_integer(),
-        Some(1)
-    );
-    assert_eq!(value["dependencies"]["libc"].as_integer(), Some(1));
-    assert_eq!(value["dependencies"]["bitflags"].as_integer(), Some(1));
-}
diff --git a/crates/toml/tests/testsuite/datetime.rs b/crates/toml/tests/testsuite/datetime.rs
index 780f1f0d..ecb2bdd0 100644
--- a/crates/toml/tests/testsuite/datetime.rs
+++ b/crates/toml/tests/testsuite/datetime.rs
@@ -42,91 +42,214 @@ fn times() {
 fn bad_times() {
     bad!(
         "foo = 199-09-09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | foo = 199-09-09
+  |          ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = 199709-09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 13
+  |
+1 | foo = 199709-09
+  |             ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = 1997-9-09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 12
+  |
+1 | foo = 1997-9-09
+  |            ^
+invalid date-time
+"
     );
     bad!(
         "foo = 1997-09-9",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 15
+  |
+1 | foo = 1997-09-9
+  |               ^
+invalid date-time
+"
     );
     bad!(
         "foo = 1997-09-0909:09:09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 17
+  |
+1 | foo = 1997-09-0909:09:09
+  |                 ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = 1997-09-09T09:09:09.",
-        "invalid date at line 1 column 7"
+        "\
+TOML parse error at line 1, column 26
+  |
+1 | foo = 1997-09-09T09:09:09.
+  |                          ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = T",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        r#"TOML parse error at line 1, column 7
+  |
+1 | foo = T
+  |       ^
+invalid string
+expected `"`, `'`
+"#
     );
     bad!(
         "foo = T.",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        r#"TOML parse error at line 1, column 7
+  |
+1 | foo = T.
+  |       ^
+invalid string
+expected `"`, `'`
+"#
     );
     bad!(
         "foo = TZ",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        r#"TOML parse error at line 1, column 7
+  |
+1 | foo = TZ
+  |       ^
+invalid string
+expected `"`, `'`
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09+",
-        "invalid date at line 1 column 7"
+        r#"TOML parse error at line 1, column 30
+  |
+1 | foo = 1997-09-09T09:09:09.09+
+  |                              ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09+09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 32
+  |
+1 | foo = 1997-09-09T09:09:09.09+09
+  |                                ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09+09:9",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 33
+  |
+1 | foo = 1997-09-09T09:09:09.09+09:9
+  |                                 ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09+0909",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 32
+  |
+1 | foo = 1997-09-09T09:09:09.09+0909
+  |                                ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09-",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 30
+  |
+1 | foo = 1997-09-09T09:09:09.09-
+  |                              ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09-09",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 32
+  |
+1 | foo = 1997-09-09T09:09:09.09-09
+  |                                ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09-09:9",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 33
+  |
+1 | foo = 1997-09-09T09:09:09.09-09:9
+  |                                 ^
+invalid time offset
+"#
     );
     bad!(
         "foo = 1997-09-09T09:09:09.09-0909",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 32
+  |
+1 | foo = 1997-09-09T09:09:09.09-0909
+  |                                ^
+invalid time offset
+"#
     );
 
     bad!(
         "foo = 1997-00-09T09:09:09.09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 12
+  |
+1 | foo = 1997-00-09T09:09:09.09Z
+  |            ^
+invalid date-time
+value is out of range
+"#
     );
     bad!(
         "foo = 1997-09-00T09:09:09.09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 15
+  |
+1 | foo = 1997-09-00T09:09:09.09Z
+  |               ^
+invalid date-time
+value is out of range
+"#
     );
     bad!(
         "foo = 1997-09-09T30:09:09.09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 17
+  |
+1 | foo = 1997-09-09T30:09:09.09Z
+  |                 ^
+expected newline, `#`
+"#
     );
     bad!(
         "foo = 1997-09-09T12:69:09.09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 21
+  |
+1 | foo = 1997-09-09T12:69:09.09Z
+  |                     ^
+invalid date-time
+value is out of range
+"#
     );
     bad!(
         "foo = 1997-09-09T12:09:69.09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        r#"TOML parse error at line 1, column 24
+  |
+1 | foo = 1997-09-09T12:09:69.09Z
+  |                        ^
+invalid date-time
+value is out of range
+"#
     );
 }
diff --git a/crates/toml/tests/testsuite/de_errors.rs b/crates/toml/tests/testsuite/de_errors.rs
index f8ff07b5..b3630bd4 100644
--- a/crates/toml/tests/testsuite/de_errors.rs
+++ b/crates/toml/tests/testsuite/de_errors.rs
@@ -83,7 +83,13 @@ fn custom_errors() {
                 # ^
         ",
         Parent<CasedString>,
-        "invalid length 0, expected a non-empty string for key `p_a` at line 2 column 19"
+        "\
+TOML parse error at line 2, column 19
+  |
+2 |             p_a = ''
+  |                   ^^
+invalid length 0, expected a non-empty string
+"
     );
 
     // Missing field in table.
@@ -93,7 +99,13 @@ fn custom_errors() {
           # ^
         ",
         Parent<CasedString>,
-        "missing field `p_b` at line 1 column 1"
+        "\
+TOML parse error at line 1, column 1
+  |
+1 | 
+  | ^
+missing field `p_b`
+"
     );
 
     // Invalid type in p_b.
@@ -104,7 +116,13 @@ fn custom_errors() {
                 # ^
         ",
         Parent<CasedString>,
-        "invalid type: integer `1`, expected a sequence for key `p_b` at line 3 column 19"
+        "\
+TOML parse error at line 3, column 19
+  |
+3 |             p_b = 1
+  |                   ^
+invalid type: integer `1`, expected a sequence
+"
     );
 
     // Sub-table in Vec is missing a field.
@@ -117,7 +135,13 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "missing field `c_b` for key `p_b` at line 4 column 17"
+        "\
+TOML parse error at line 4, column 17
+  |
+4 |                 {c_a = 'a'}
+  |                 ^^^^^^^^^^^
+missing field `c_b`
+"
     );
 
     // Sub-table in Vec has a field with a bad value.
@@ -130,7 +154,13 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "invalid value: string \"*\", expected all lowercase or all uppercase for key `p_b` at line 4 column 35"
+        "\
+TOML parse error at line 4, column 35
+  |
+4 |                 {c_a = 'a', c_b = '*'}
+  |                                   ^^^
+invalid value: string \"*\", expected all lowercase or all uppercase
+"
     );
 
     // Sub-table in Vec is missing a field.
@@ -144,7 +174,13 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "missing field `c_b` for key `p_b` at line 5 column 17"
+        "\
+TOML parse error at line 5, column 17
+  |
+5 |                 {c_a = 'aa'}
+  |                 ^^^^^^^^^^^^
+missing field `c_b`
+"
     );
 
     // Sub-table in the middle of a Vec is missing a field.
@@ -159,7 +195,13 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "missing field `c_b` for key `p_b` at line 5 column 17"
+        "\
+TOML parse error at line 5, column 17
+  |
+5 |                 {c_a = 'aa'},
+  |                 ^^^^^^^^^^^^
+missing field `c_b`
+"
     );
 
     // Sub-table in the middle of a Vec has a field with a bad value.
@@ -174,11 +216,16 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "invalid type: integer `1`, expected a string for key `p_b` at line 5 column 36"
+        "\
+TOML parse error at line 5, column 36
+  |
+5 |                 {c_a = 'aa', c_b = 1},
+  |                                    ^
+invalid type: integer `1`, expected a string
+"
     );
 
     // Sub-table in the middle of a Vec has an extra field.
-    // FIXME: This location could be better.
     bad!(
         "
             p_a = 'a'
@@ -191,7 +238,13 @@ fn custom_errors() {
             ]
         ",
         Parent<CasedString>,
-        "unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 5 column 17"
+        "\
+TOML parse error at line 5, column 42
+  |
+5 |                 {c_a = 'aa', c_b = 'bb', c_d = 'd'},
+  |                                          ^^^
+unknown field `c_d`, expected `c_a` or `c_b`
+"
     );
 
     // Sub-table in the middle of a Vec is missing a field.
@@ -214,7 +267,13 @@ fn custom_errors() {
             c_b = 'bbbb'
         ",
         Parent<CasedString>,
-        "missing field `c_b` for key `p_b` at line 12 column 13"
+        "\
+TOML parse error at line 6, column 13
+  |
+6 |             [[p_b]]
+  |             ^^^^^^^^^^^^^^^^^^^
+missing field `c_b`
+"
     );
 
     // Sub-table in the middle of a Vec has a field with a bad value.
@@ -233,11 +292,16 @@ fn custom_errors() {
             c_b = 'bbb'
         ",
         Parent<CasedString>,
-        "invalid value: string \"*\", expected all lowercase or all uppercase for key `p_b.c_b` at line 8 column 19"
+        "\
+TOML parse error at line 8, column 19
+  |
+8 |             c_b = '*'
+  |                   ^^^
+invalid value: string \"*\", expected all lowercase or all uppercase
+"
     );
 
     // Sub-table in the middle of a Vec has an extra field.
-    // FIXME: This location is pretty off.
     bad!(
         "
             p_a = 'a'
@@ -247,16 +311,22 @@ fn custom_errors() {
             [[p_b]]
             c_a = 'aa'
             c_d = 'dd' # unknown field
+          # ^
             [[p_b]]
             c_a = 'aaa'
             c_b = 'bbb'
             [[p_b]]
-          # ^
             c_a = 'aaaa'
             c_b = 'bbbb'
         ",
         Parent<CasedString>,
-        "unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 12 column 13"
+        "\
+TOML parse error at line 8, column 13
+  |
+8 |             c_d = 'dd' # unknown field
+  |             ^^^
+unknown field `c_d`, expected `c_a` or `c_b`
+"
     );
 }
 
@@ -268,7 +338,13 @@ fn serde_derive_deserialize_errors() {
           # ^
         ",
         Parent<String>,
-        "missing field `p_b` at line 1 column 1"
+        "\
+TOML parse error at line 1, column 1
+  |
+1 | 
+  | ^
+missing field `p_b`
+"
     );
 
     bad!(
@@ -280,7 +356,13 @@ fn serde_derive_deserialize_errors() {
             ]
         ",
         Parent<String>,
-        "missing field `c_b` for key `p_b` at line 4 column 17"
+        "\
+TOML parse error at line 4, column 17
+  |
+4 |                 {c_a = ''}
+  |                 ^^^^^^^^^^
+missing field `c_b`
+"
     );
 
     bad!(
@@ -292,7 +374,13 @@ fn serde_derive_deserialize_errors() {
             ]
         ",
         Parent<String>,
-        "invalid type: integer `1`, expected a string for key `p_b` at line 4 column 34"
+        "\
+TOML parse error at line 4, column 34
+  |
+4 |                 {c_a = '', c_b = 1}
+  |                                  ^
+invalid type: integer `1`, expected a string
+"
     );
 
     // FIXME: This location could be better.
@@ -305,7 +393,13 @@ fn serde_derive_deserialize_errors() {
             ]
         ",
         Parent<String>,
-        "unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 4 column 17"
+        "\
+TOML parse error at line 4, column 38
+  |
+4 |                 {c_a = '', c_b = '', c_d = ''},
+  |                                      ^^^
+unknown field `c_d`, expected `c_a` or `c_b`
+"
     );
 
     bad!(
@@ -317,7 +411,13 @@ fn serde_derive_deserialize_errors() {
             ]
         ",
         Parent<String>,
-        "invalid type: integer `1`, expected a string for key `p_b` at line 4 column 34"
+        "\
+TOML parse error at line 4, column 34
+  |
+4 |                 {c_a = '', c_b = 1, c_d = ''},
+  |                                  ^
+invalid type: integer `1`, expected a string
+"
     );
 }
 
@@ -331,7 +431,13 @@ fn error_handles_crlf() {
          a = 2\r\n\
          ",
         toml::Value,
-        "duplicate key: `a` for key `t2` at line 3 column 1"
+        "\
+TOML parse error at line 5, column 1
+  |
+5 | a = 2
+  | ^
+duplicate key `a` in table `t2`
+"
     );
 
     // Should be the same as above.
@@ -343,6 +449,12 @@ fn error_handles_crlf() {
          a = 2\n\
          ",
         toml::Value,
-        "duplicate key: `a` for key `t2` at line 3 column 1"
+        "\
+TOML parse error at line 5, column 1
+  |
+5 | a = 2
+  | ^
+duplicate key `a` in table `t2`
+"
     );
 }
diff --git a/crates/toml/tests/testsuite/enum_external_deserialize.rs b/crates/toml/tests/testsuite/enum_external_deserialize.rs
index e3450c8f..e1a068cc 100644
--- a/crates/toml/tests/testsuite/enum_external_deserialize.rs
+++ b/crates/toml/tests/testsuite/enum_external_deserialize.rs
@@ -23,39 +23,98 @@ struct Multi {
     enums: Vec<TheEnum>,
 }
 
+fn value_from_str<T>(s: &'_ str) -> Result<T, toml::de::Error>
+where
+    T: serde::de::DeserializeOwned,
+{
+    T::deserialize(toml::ValueDeserializer::new(s))
+}
+
 #[test]
 fn invalid_variant_returns_error_with_good_message_string() {
-    let error = toml::from_str::<TheEnum>("\"NonExistent\"").unwrap_err();
+    let error = value_from_str::<TheEnum>("\"NonExistent\"").unwrap_err();
+    snapbox::assert_eq(
+        r#"unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`
+"#,
+        error.to_string(),
+    );
 
+    let error = toml::from_str::<Val>("val = \"NonExistent\"").unwrap_err();
     snapbox::assert_eq(
-        "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`",
+        r#"TOML parse error at line 1, column 7
+  |
+1 | val = "NonExistent"
+  |       ^^^^^^^^^^^^^
+unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`
+"#,
         error.to_string(),
     );
 }
 
 #[test]
 fn invalid_variant_returns_error_with_good_message_inline_table() {
-    let error = toml::from_str::<TheEnum>("{ NonExistent = {} }").unwrap_err();
+    let error = value_from_str::<TheEnum>("{ NonExistent = {} }").unwrap_err();
     snapbox::assert_eq(
-        "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`",
+        r#"unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`
+"#,
+        error.to_string(),
+    );
+
+    let error = toml::from_str::<Val>("val = { NonExistent = {} }").unwrap_err();
+    snapbox::assert_eq(
+        r#"TOML parse error at line 1, column 9
+  |
+1 | val = { NonExistent = {} }
+  |         ^^^^^^^^^^^
+unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`
+"#,
         error.to_string(),
     );
 }
 
 #[test]
 fn extra_field_returns_expected_empty_table_error() {
-    let error = toml::from_str::<TheEnum>("{ Plain = { extra_field = 404 } }").unwrap_err();
+    let error = value_from_str::<TheEnum>("{ Plain = { extra_field = 404 } }").unwrap_err();
+    snapbox::assert_eq(
+        r#"expected empty table
+"#,
+        error.to_string(),
+    );
 
-    snapbox::assert_eq("expected empty table", error.to_string());
+    let error = toml::from_str::<Val>("val = { Plain = { extra_field = 404 } }").unwrap_err();
+    snapbox::assert_eq(
+        r#"TOML parse error at line 1, column 17
+  |
+1 | val = { Plain = { extra_field = 404 } }
+  |                 ^^^^^^^^^^^^^^^^^^^^^
+expected empty table
+"#,
+        error.to_string(),
+    );
 }
 
 #[test]
 fn extra_field_returns_expected_empty_table_error_struct_variant() {
-    let error = toml::from_str::<TheEnum>("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }")
+    let error = value_from_str::<TheEnum>("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }")
         .unwrap_err();
 
     snapbox::assert_eq(
-        r#"unexpected keys in table: `["extra_0", "extra_1"]`, available keys: `["value"]`"#,
+        r#"unexpected keys in table: extra_0, extra_1, available keys: value
+"#,
+        error.to_string(),
+    );
+
+    let error =
+        toml::from_str::<Val>("val = { Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }")
+            .unwrap_err();
+
+    snapbox::assert_eq(
+        r#"TOML parse error at line 1, column 33
+  |
+1 | val = { Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }
+  |                                 ^^^^^^^
+unexpected keys in table: extra_0, extra_1, available keys: value
+"#,
         error.to_string(),
     );
 }
@@ -65,12 +124,19 @@ mod enum_unit {
 
     #[test]
     fn from_str() {
-        assert_eq!(TheEnum::Plain, toml::from_str("\"Plain\"").unwrap());
+        assert_eq!(TheEnum::Plain, value_from_str("\"Plain\"").unwrap());
+
+        assert_eq!(
+            Val {
+                val: TheEnum::Plain
+            },
+            toml::from_str("val = \"Plain\"").unwrap()
+        );
     }
 
     #[test]
     fn from_inline_table() {
-        assert_eq!(TheEnum::Plain, toml::from_str("{ Plain = {} }").unwrap());
+        assert_eq!(TheEnum::Plain, value_from_str("{ Plain = {} }").unwrap());
         assert_eq!(
             Val {
                 val: TheEnum::Plain
@@ -80,7 +146,7 @@ mod enum_unit {
     }
 
     #[test]
-    fn from_dotted_table() {
+    fn from_std_table() {
         assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap());
     }
 }
@@ -92,7 +158,7 @@ mod enum_tuple {
     fn from_inline_table() {
         assert_eq!(
             TheEnum::Tuple(-123, true),
-            toml::from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap()
+            value_from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap()
         );
         assert_eq!(
             Val {
@@ -103,7 +169,7 @@ mod enum_tuple {
     }
 
     #[test]
-    fn from_dotted_table() {
+    fn from_std_table() {
         assert_eq!(
             TheEnum::Tuple(-123, true),
             toml::from_str(
@@ -124,7 +190,7 @@ mod enum_newtype {
     fn from_inline_table() {
         assert_eq!(
             TheEnum::NewType("value".to_string()),
-            toml::from_str(r#"{ NewType = "value" }"#).unwrap()
+            value_from_str(r#"{ NewType = "value" }"#).unwrap()
         );
         assert_eq!(
             Val {
@@ -135,8 +201,7 @@ mod enum_newtype {
     }
 
     #[test]
-    #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"]
-    fn from_dotted_table() {
+    fn from_std_table() {
         assert_eq!(
             TheEnum::NewType("value".to_string()),
             toml::from_str(r#"NewType = "value""#).unwrap()
@@ -162,7 +227,7 @@ mod enum_struct {
     fn from_inline_table() {
         assert_eq!(
             TheEnum::Struct { value: -123 },
-            toml::from_str("{ Struct = { value = -123 } }").unwrap()
+            value_from_str("{ Struct = { value = -123 } }").unwrap()
         );
         assert_eq!(
             Val {
@@ -173,7 +238,7 @@ mod enum_struct {
     }
 
     #[test]
-    fn from_dotted_table() {
+    fn from_std_table() {
         assert_eq!(
             TheEnum::Struct { value: -123 },
             toml::from_str(
@@ -186,7 +251,7 @@ mod enum_struct {
     }
 
     #[test]
-    fn from_nested_dotted_table() {
+    fn from_nested_std_table() {
         assert_eq!(
             OuterStruct {
                 inner: TheEnum::Struct { value: -123 }
@@ -227,8 +292,7 @@ mod enum_array {
     }
 
     #[test]
-    #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"]
-    fn from_dotted_table() {
+    fn from_std_table() {
         let toml_str = r#"[[enums]]
             Plain = {}
 
diff --git a/crates/toml/tests/testsuite/invalid_misc.rs b/crates/toml/tests/testsuite/invalid_misc.rs
index f5d67cf4..c7497343 100644
--- a/crates/toml/tests/testsuite/invalid_misc.rs
+++ b/crates/toml/tests/testsuite/invalid_misc.rs
@@ -9,25 +9,99 @@ macro_rules! bad {
 
 #[test]
 fn bad() {
-    bad!("a = 01", "invalid number at line 1 column 6");
-    bad!("a = 1__1", "invalid number at line 1 column 5");
-    bad!("a = 1_", "invalid number at line 1 column 5");
-    bad!("''", "expected an equals, found eof at line 1 column 3");
-    bad!("a = 9e99999", "invalid number at line 1 column 5");
+    bad!(
+        "a = 01",
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = 01
+  |      ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = 1__1",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 1__1
+  |       ^
+invalid integer
+expected digit
+"
+    );
+    bad!(
+        "a = 1_",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 1_
+  |       ^
+invalid integer
+expected digit
+"
+    );
+    bad!(
+        "''",
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | ''
+  |   ^
+expected `.`, `=`
+"
+    );
+    bad!(
+        "a = 9e99999",
+        "\
+TOML parse error at line 1, column 5
+  |
+1 | a = 9e99999
+  |     ^
+invalid floating-point number
+"
+    );
 
     bad!(
         "a = \"\u{7f}\"",
-        "invalid character in string: `\\u{7f}` at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = \"\u{7f}\"
+  |      ^
+invalid basic string
+"
     );
     bad!(
         "a = '\u{7f}'",
-        "invalid character in string: `\\u{7f}` at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = '\u{7f}'
+  |      ^
+invalid literal string
+"
     );
 
-    bad!("a = -0x1", "invalid number at line 1 column 5");
+    bad!(
+        "a = -0x1",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = -0x1
+  |       ^
+expected newline, `#`
+"
+    );
     bad!(
         "a = 0x-1",
-        "failed to parse datetime for key `a` at line 1 column 5"
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 0x-1
+  |       ^
+invalid hexadecimal integer
+"
     );
 
     // Dotted keys.
@@ -35,15 +109,33 @@ fn bad() {
         "a.b.c = 1
          a.b = 2
         ",
-        "duplicate key: `b` for key `a` at line 1 column 9"
+        "\
+TOML parse error at line 2, column 10
+  |
+2 |          a.b = 2
+  |          ^
+duplicate key `b` in document root
+"
     );
     bad!(
         "a = 1
          a.b = 2",
-        "dotted key attempted to extend non-table type at line 1 column 5"
+        "\
+TOML parse error at line 2, column 10
+  |
+2 |          a.b = 2
+  |          ^
+dotted key `a` attempted to extend non-table type (integer)
+"
     );
     bad!(
         "a = {k1 = 1, k1.name = \"joe\"}",
-        "dotted key attempted to extend non-table type at line 1 column 11"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = {k1 = 1, k1.name = \"joe\"}
+  |      ^
+dotted key `k1` attempted to extend non-table type (integer)
+"
     );
 }
diff --git a/crates/toml/tests/testsuite/main.rs b/crates/toml/tests/testsuite/main.rs
index 6437cd19..649c2c95 100644
--- a/crates/toml/tests/testsuite/main.rs
+++ b/crates/toml/tests/testsuite/main.rs
@@ -1,6 +1,5 @@
 #![recursion_limit = "256"]
 
-mod backcompat;
 mod datetime;
 mod de_errors;
 mod display;
diff --git a/crates/toml/tests/testsuite/parser.rs b/crates/toml/tests/testsuite/parser.rs
index ce77b5cb..0d2324b8 100644
--- a/crates/toml/tests/testsuite/parser.rs
+++ b/crates/toml/tests/testsuite/parser.rs
@@ -184,30 +184,83 @@ name = "plantain"
 
 #[test]
 fn stray_cr() {
-    bad!("\r", "unexpected character found: `\\r` at line 1 column 1");
+    bad!(
+        "\r",
+        "\
+TOML parse error at line 1, column 1
+  |
+1 | \r
+  | ^
+
+"
+    );
     bad!(
         "a = [ \r ]",
-        "unexpected character found: `\\r` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = [ \r
+ ]
+  |       ^
+invalid array
+expected `]`
+"
     );
     bad!(
         "a = \"\"\"\r\"\"\"",
-        "invalid character in string: `\\r` at line 1 column 8"
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | a = \"\"\"\r
+\"\"\"
+  |        ^
+invalid multiline basic string
+"
     );
     bad!(
         "a = \"\"\"\\  \r  \"\"\"",
-        "invalid escape character in string: ` ` at line 1 column 9"
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | a = \"\"\"\\  \r
+  \"\"\"
+  |          ^
+invalid escape sequence
+expected `b`, `f`, `n`, `r`, `t`, `u`, `U`, `\\`, `\"`
+"
     );
     bad!(
         "a = '''\r'''",
-        "invalid character in string: `\\r` at line 1 column 8"
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | a = '''\r
+'''
+  |        ^
+invalid multiline literal string
+"
     );
     bad!(
         "a = '\r'",
-        "invalid character in string: `\\r` at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = '\r
+'
+  |      ^
+invalid literal string
+"
     );
     bad!(
         "a = \"\r\"",
-        "invalid character in string: `\\r` at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = \"\r
+\"
+  |      ^
+invalid basic string
+"
     );
 }
 
@@ -237,37 +290,187 @@ fn literal_eats_crlf() {
 
 #[test]
 fn string_no_newline() {
-    bad!("a = \"\n\"", "newline in string found at line 1 column 6");
-    bad!("a = '\n'", "newline in string found at line 1 column 6");
+    bad!(
+        "a = \"\n\"",
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = \"
+  |      ^
+invalid basic string
+"
+    );
+    bad!(
+        "a = '\n'",
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = '
+  |      ^
+invalid literal string
+"
+    );
 }
 
 #[test]
 fn bad_leading_zeros() {
-    bad!("a = 00", "invalid number at line 1 column 6");
-    bad!("a = -00", "invalid number at line 1 column 7");
-    bad!("a = +00", "invalid number at line 1 column 7");
-    bad!("a = 00.0", "invalid number at line 1 column 6");
-    bad!("a = -00.0", "invalid number at line 1 column 7");
-    bad!("a = +00.0", "invalid number at line 1 column 7");
+    bad!(
+        "a = 00",
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = 00
+  |      ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = -00",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = -00
+  |       ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = +00",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = +00
+  |       ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = 00.0",
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = 00.0
+  |      ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = -00.0",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = -00.0
+  |       ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "a = +00.0",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = +00.0
+  |       ^
+expected newline, `#`
+"
+    );
     bad!(
         "a = 9223372036854775808",
-        "invalid number at line 1 column 5"
+        "\
+TOML parse error at line 1, column 5
+  |
+1 | a = 9223372036854775808
+  |     ^
+number too large to fit in target type
+"
     );
     bad!(
         "a = -9223372036854775809",
-        "invalid number at line 1 column 5"
+        "\
+TOML parse error at line 1, column 5
+  |
+1 | a = -9223372036854775809
+  |     ^
+number too small to fit in target type
+"
     );
 }
 
 #[test]
 fn bad_floats() {
-    bad!("a = 0.", "invalid number at line 1 column 7");
-    bad!("a = 0.e", "invalid number at line 1 column 7");
-    bad!("a = 0.E", "invalid number at line 1 column 7");
-    bad!("a = 0.0E", "invalid number at line 1 column 5");
-    bad!("a = 0.0e", "invalid number at line 1 column 5");
-    bad!("a = 0.0e-", "invalid number at line 1 column 9");
-    bad!("a = 0.0e+", "invalid number at line 1 column 5");
+    bad!(
+        "a = 0.",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 0.
+  |       ^
+invalid floating-point number
+expected digit
+"
+    );
+    bad!(
+        "a = 0.e",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 0.e
+  |       ^
+invalid floating-point number
+expected digit
+"
+    );
+    bad!(
+        "a = 0.E",
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | a = 0.E
+  |       ^
+invalid floating-point number
+expected digit
+"
+    );
+    bad!(
+        "a = 0.0E",
+        "\
+TOML parse error at line 1, column 9
+  |
+1 | a = 0.0E
+  |         ^
+invalid floating-point number
+"
+    );
+    bad!(
+        "a = 0.0e",
+        "\
+TOML parse error at line 1, column 9
+  |
+1 | a = 0.0e
+  |         ^
+invalid floating-point number
+"
+    );
+    bad!(
+        "a = 0.0e-",
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | a = 0.0e-
+  |          ^
+invalid floating-point number
+"
+    );
+    bad!(
+        "a = 0.0e+",
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | a = 0.0e+
+  |          ^
+invalid floating-point number
+"
+    );
 }
 
 #[test]
@@ -330,44 +533,114 @@ fn bare_key_names() {
 fn bad_keys() {
     bad!(
         "key\n=3",
-        "expected an equals, found a newline at line 1 column 4"
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | key
+  |    ^
+expected `.`, `=`
+"
     );
     bad!(
         "key=\n3",
-        "expected a value, found a newline at line 1 column 5"
+        "\
+TOML parse error at line 1, column 5
+  |
+1 | key=
+  |     ^
+invalid string
+expected `\"`, `'`
+"
     );
     bad!(
         "key|=3",
-        "unexpected character found: `|` at line 1 column 4"
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | key|=3
+  |    ^
+expected `.`, `=`
+"
     );
     bad!(
         "=3",
-        "expected a table key, found an equals at line 1 column 1"
+        "\
+TOML parse error at line 1, column 1
+  |
+1 | =3
+  | ^
+invalid key
+"
     );
     bad!(
         "\"\"|=3",
-        "unexpected character found: `|` at line 1 column 3"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | \"\"|=3
+  |   ^
+expected `.`, `=`
+"
+    );
+    bad!(
+        "\"\n\"|=3",
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | \"
+  |  ^
+invalid basic string
+"
     );
-    bad!("\"\n\"|=3", "newline in string found at line 1 column 2");
     bad!(
         "\"\r\"|=3",
-        "invalid character in string: `\\r` at line 1 column 2"
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | \"\r\"|=3
+  |  ^
+invalid basic string
+"
     );
     bad!(
         "''''''=3",
-        "multiline strings are not allowed for key at line 1 column 1"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | ''''''=3
+  |   ^
+expected `.`, `=`
+"
     );
     bad!(
         "\"\"\"\"\"\"=3",
-        "multiline strings are not allowed for key at line 1 column 1"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | \"\"\"\"\"\"=3
+  |   ^
+expected `.`, `=`
+"
     );
     bad!(
         "'''key'''=3",
-        "multiline strings are not allowed for key at line 1 column 1"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | '''key'''=3
+  |   ^
+expected `.`, `=`
+"
     );
     bad!(
         "\"\"\"key\"\"\"=3",
-        "multiline strings are not allowed for key at line 1 column 1"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | \"\"\"key\"\"\"=3
+  |   ^
+expected `.`, `=`
+"
     );
 }
 
@@ -375,38 +648,140 @@ fn bad_keys() {
 fn bad_table_names() {
     bad!(
         "[]",
-        "expected a table key, found a right bracket at line 1 column 2"
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | []
+  |  ^
+invalid key
+"
     );
     bad!(
         "[.]",
-        "expected a table key, found a period at line 1 column 2"
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | [.]
+  |  ^
+invalid key
+"
     );
     bad!(
         "[a.]",
-        "expected a table key, found a right bracket at line 1 column 4"
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | [a.]
+  |   ^
+invalid table header
+expected `.`, `]`
+"
+    );
+    bad!(
+        "[!]",
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | [!]
+  |  ^
+invalid key
+"
+    );
+    bad!(
+        "[\"\n\"]",
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | [\"
+  |   ^
+invalid basic string
+"
     );
-    bad!("[!]", "unexpected character found: `!` at line 1 column 2");
-    bad!("[\"\n\"]", "newline in string found at line 1 column 3");
     bad!(
         "[a.b]\n[a.\"b\"]",
-        "redefinition of table `a.b` for key `a.b` at line 2 column 1"
+        "\
+TOML parse error at line 2, column 1
+  |
+2 | [a.\"b\"]
+  | ^
+invalid table header
+duplicate key `b` in table `a`
+"
+    );
+    bad!(
+        "[']",
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | [']
+  |    ^
+invalid literal string
+"
+    );
+    bad!(
+        "[''']",
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | [''']
+  |    ^
+invalid table header
+expected `.`, `]`
+"
     );
-    bad!("[']", "unterminated string at line 1 column 2");
-    bad!("[''']", "unterminated string at line 1 column 2");
     bad!(
         "['''''']",
-        "multiline strings are not allowed for key at line 1 column 2"
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | ['''''']
+  |    ^
+invalid table header
+expected `.`, `]`
+"
     );
     bad!(
         "['''foo''']",
-        "multiline strings are not allowed for key at line 1 column 2"
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | ['''foo''']
+  |    ^
+invalid table header
+expected `.`, `]`
+"
     );
     bad!(
         "[\"\"\"bar\"\"\"]",
-        "multiline strings are not allowed for key at line 1 column 2"
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | [\"\"\"bar\"\"\"]
+  |    ^
+invalid table header
+expected `.`, `]`
+"
+    );
+    bad!(
+        "['\n']",
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | ['
+  |   ^
+invalid literal string
+"
+    );
+    bad!(
+        "['\r\n']",
+        "\
+TOML parse error at line 1, column 3
+  |
+1 | ['
+  |   ^
+invalid literal string
+"
     );
-    bad!("['\n']", "newline in string found at line 1 column 3");
-    bad!("['\r\n']", "newline in string found at line 1 column 3");
 }
 
 #[test]
@@ -431,7 +806,16 @@ fn table_names() {
 
 #[test]
 fn invalid_bare_numeral() {
-    bad!("4", "expected an equals, found eof at line 1 column 2");
+    bad!(
+        "4",
+        "\
+TOML parse error at line 1, column 2
+  |
+1 | 4
+  |  ^
+expected `.`, `=`
+"
+    );
 }
 
 #[test]
@@ -444,23 +828,57 @@ fn inline_tables() {
 
     bad!(
         "a = {a=1,}",
-        "expected a table key, found a right brace at line 1 column 10"
+        "\
+TOML parse error at line 1, column 9
+  |
+1 | a = {a=1,}
+  |         ^
+invalid inline table
+expected `}`
+"
     );
     bad!(
         "a = {,}",
-        "expected a table key, found a comma at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = {,}
+  |      ^
+invalid inline table
+expected `}`
+"
     );
     bad!(
         "a = {a=1,a=1}",
-        "duplicate key: `a` for key `a` at line 1 column 5"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = {a=1,a=1}
+  |      ^
+duplicate key `a`
+"
     );
     bad!(
         "a = {\n}",
-        "expected a table key, found a newline at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = {
+  |      ^
+invalid inline table
+expected `}`
+"
     );
     bad!(
         "a = {",
-        "expected a table key, found eof at line 1 column 6"
+        "\
+TOML parse error at line 1, column 6
+  |
+1 | a = {
+  |      ^
+invalid inline table
+expected `}`
+"
     );
 
     "a = {a=[\n]}".parse::<Value>().unwrap();
@@ -487,20 +905,62 @@ fn number_underscores() {
 
 #[test]
 fn bad_underscores() {
-    bad!("foo = 0_", "invalid number at line 1 column 7");
-    bad!("foo = 0__0", "invalid number at line 1 column 7");
+    bad!(
+        "foo = 0_",
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | foo = 0_
+  |        ^
+expected newline, `#`
+"
+    );
+    bad!(
+        "foo = 0__0",
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | foo = 0__0
+  |        ^
+expected newline, `#`
+"
+    );
     bad!(
         "foo = __0",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | foo = __0
+  |       ^
+invalid integer
+expected leading digit
+"
+    );
+    bad!(
+        "foo = 1_0_",
+        "\
+TOML parse error at line 1, column 11
+  |
+1 | foo = 1_0_
+  |           ^
+invalid integer
+expected digit
+"
     );
-    bad!("foo = 1_0_", "invalid number at line 1 column 7");
 }
 
 #[test]
 fn bad_unicode_codepoint() {
     bad!(
         "foo = \"\\uD800\"",
-        "invalid escape value: `55296` at line 1 column 9"
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | foo = \"\\uD800\"
+  |          ^
+invalid unicode 4-digit hex code
+value is out of range
+"
     );
 }
 
@@ -508,14 +968,44 @@ fn bad_unicode_codepoint() {
 fn bad_strings() {
     bad!(
         "foo = \"\\uxx\"",
-        "invalid hex escape character in string: `x` at line 1 column 10"
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | foo = \"\\uxx\"
+  |          ^
+invalid unicode 4-digit hex code
+"
     );
     bad!(
         "foo = \"\\u\"",
-        "invalid hex escape character in string: `\\\"` at line 1 column 10"
+        "\
+TOML parse error at line 1, column 10
+  |
+1 | foo = \"\\u\"
+  |          ^
+invalid unicode 4-digit hex code
+"
+    );
+    bad!(
+        "foo = \"\\",
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | foo = \"\\
+  |        ^
+invalid basic string
+"
+    );
+    bad!(
+        "foo = '",
+        "\
+TOML parse error at line 1, column 8
+  |
+1 | foo = '
+  |        ^
+invalid literal string
+"
     );
-    bad!("foo = \"\\", "unterminated string at line 1 column 7");
-    bad!("foo = '", "unterminated string at line 1 column 7");
 }
 
 #[test]
@@ -538,19 +1028,45 @@ fn booleans() {
 
     bad!(
         "foo = true2",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        "\
+TOML parse error at line 1, column 11
+  |
+1 | foo = true2
+  |           ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = false2",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        "\
+TOML parse error at line 1, column 12
+  |
+1 | foo = false2
+  |            ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = t1",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | foo = t1
+  |       ^
+invalid string
+expected `\"`, `'`
+"
     );
     bad!(
         "foo = f2",
-        "invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
+        "\
+TOML parse error at line 1, column 7
+  |
+1 | foo = f2
+  |       ^
+invalid string
+expected `\"`, `'`
+"
     );
 }
 
@@ -562,28 +1078,56 @@ fn bad_nesting() {
         [[a]]
         b = 5
         ",
-        "duplicate key: `a` at line 3 column 9"
+        "\
+TOML parse error at line 3, column 9
+  |
+3 |         [[a]]
+  |         ^
+invalid table header
+duplicate key `a` in document root
+"
     );
     bad!(
         "
         a = 1
         [a.b]
         ",
-        "duplicate key: `a` at line 3 column 9"
+        "\
+TOML parse error at line 3, column 9
+  |
+3 |         [a.b]
+  |         ^
+invalid table header
+dotted key `a` attempted to extend non-table type (integer)
+"
     );
     bad!(
         "
         a = []
         [a.b]
         ",
-        "duplicate key: `a` at line 3 column 9"
+        "\
+TOML parse error at line 3, column 9
+  |
+3 |         [a.b]
+  |         ^
+invalid table header
+dotted key `a` attempted to extend non-table type (array)
+"
     );
     bad!(
         "
         a = []
         [[a.b]]
         ",
-        "duplicate key: `a` at line 3 column 9"
+        "\
+TOML parse error at line 3, column 9
+  |
+3 |         [[a.b]]
+  |         ^
+invalid table header
+dotted key `a` attempted to extend non-table type (array)
+"
     );
     bad!(
         "
@@ -592,7 +1136,14 @@ fn bad_nesting() {
         [a.b]
         c = 2
         ",
-        "duplicate key: `b` for key `a` at line 4 column 9"
+        "\
+TOML parse error at line 4, column 9
+  |
+4 |         [a.b]
+  |         ^
+invalid table header
+duplicate key `b` in table `a`
+"
     );
 }
 
@@ -606,7 +1157,14 @@ fn bad_table_redefine() {
         foo=\"bar\"
         [a]
         ",
-        "redefinition of table `a` for key `a` at line 6 column 9"
+        "\
+TOML parse error at line 6, column 9
+  |
+6 |         [a]
+  |         ^
+invalid table header
+duplicate key `a` in document root
+"
     );
     bad!(
         "
@@ -615,7 +1173,14 @@ fn bad_table_redefine() {
         b = { foo = \"bar\" }
         [a]
         ",
-        "redefinition of table `a` for key `a` at line 5 column 9"
+        "\
+TOML parse error at line 5, column 9
+  |
+5 |         [a]
+  |         ^
+invalid table header
+duplicate key `a` in document root
+"
     );
     bad!(
         "
@@ -623,7 +1188,14 @@ fn bad_table_redefine() {
         b = {}
         [a.b]
         ",
-        "duplicate key: `b` for key `a` at line 4 column 9"
+        "\
+TOML parse error at line 4, column 9
+  |
+4 |         [a.b]
+  |         ^
+invalid table header
+duplicate key `b` in table `a`
+"
     );
 
     bad!(
@@ -632,7 +1204,14 @@ fn bad_table_redefine() {
         b = {}
         [a]
         ",
-        "redefinition of table `a` for key `a` at line 4 column 9"
+        "\
+TOML parse error at line 4, column 9
+  |
+4 |         [a]
+  |         ^
+invalid table header
+duplicate key `a` in document root
+"
     );
 }
 
@@ -652,34 +1231,78 @@ fn datetimes() {
     t!("2016-09-09T09:09:09.123456789-02:00");
     bad!(
         "foo = 2016-09-09T09:09:09.Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 26
+  |
+1 | foo = 2016-09-09T09:09:09.Z
+  |                          ^
+expected newline, `#`
+"
     );
     bad!(
         "foo = 2016-9-09T09:09:09Z",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 12
+  |
+1 | foo = 2016-9-09T09:09:09Z
+  |            ^
+invalid date-time
+"
     );
     bad!(
         "foo = 2016-09-09T09:09:09+2:00",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 27
+  |
+1 | foo = 2016-09-09T09:09:09+2:00
+  |                           ^
+invalid time offset
+"
     );
     bad!(
         "foo = 2016-09-09T09:09:09-2:00",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 27
+  |
+1 | foo = 2016-09-09T09:09:09-2:00
+  |                           ^
+invalid time offset
+"
     );
     bad!(
         "foo = 2016-09-09T09:09:09Z-2:00",
-        "failed to parse datetime for key `foo` at line 1 column 7"
+        "\
+TOML parse error at line 1, column 27
+  |
+1 | foo = 2016-09-09T09:09:09Z-2:00
+  |                           ^
+expected newline, `#`
+"
     );
 }
 
 #[test]
 fn require_newline_after_value() {
-    bad!("0=0r=false", "invalid number at line 1 column 3");
+    bad!(
+        "0=0r=false",
+        "\
+TOML parse error at line 1, column 4
+  |
+1 | 0=0r=false
+  |    ^
+expected newline, `#`
+"
+    );
     bad!(
         r#"
 0=""o=""m=""r=""00="0"q="""0"""e="""0"""
 "#,
-        "expected newline, found an identifier at line 2 column 5"
+        r#"TOML parse error at line 2, column 5
+  |
+2 | 0=""o=""m=""r=""00="0"q="""0"""e="""0"""
+  |     ^
+expected newline, `#`
+"#
     );
     bad!(
         r#"
@@ -688,24 +1311,44 @@ fn require_newline_after_value() {
 0="0"[[0000l0]]
 0="0"l="0"
 "#,
-        "expected newline, found a left bracket at line 3 column 6"
+        r#"TOML parse error at line 3, column 6
+  |
+3 | 0="0"[[0000l0]]
+  |      ^
+expected newline, `#`
+"#
     );
     bad!(
         r#"
 0=[0]00=[0,0,0]t=["0","0","0"]s=[1000-00-00T00:00:00Z,2000-00-00T00:00:00Z]
 "#,
-        "expected newline, found an identifier at line 2 column 6"
+        r#"TOML parse error at line 2, column 6
+  |
+2 | 0=[0]00=[0,0,0]t=["0","0","0"]s=[1000-00-00T00:00:00Z,2000-00-00T00:00:00Z]
+  |      ^
+expected newline, `#`
+"#
     );
     bad!(
         r#"
 0=0r0=0r=false
 "#,
-        "invalid number at line 2 column 3"
+        r#"TOML parse error at line 2, column 4
+  |
+2 | 0=0r0=0r=false
+  |    ^
+expected newline, `#`
+"#
     );
     bad!(
         r#"
 0=0r0=0r=falsefal=false
 "#,
-        "invalid number at line 2 column 3"
+        r#"TOML parse error at line 2, column 4
+  |
+2 | 0=0r0=0r=falsefal=false
+  |    ^
+expected newline, `#`
+"#
     );
 }
diff --git a/crates/toml/tests/testsuite/serde.rs b/crates/toml/tests/testsuite/serde.rs
index 309f7e54..44fee218 100644
--- a/crates/toml/tests/testsuite/serde.rs
+++ b/crates/toml/tests/testsuite/serde.rs
@@ -272,8 +272,13 @@ fn type_errors() {
         Table(map! {
             bar: Value::String("a".to_string())
         }),
-        "invalid type: string \"a\", expected isize for key `bar` at line 1 column 7",
-        "invalid type: string \"a\", expected isize for key `bar`"
+        r#"TOML parse error at line 1, column 7
+  |
+1 | bar = "a"
+  |       ^^^
+invalid type: string "a", expected isize
+"#,
+        "invalid type: string \"a\", expected isize\n"
     }
 
     #[derive(Deserialize)]
@@ -289,8 +294,13 @@ fn type_errors() {
                 bar: Value::String("a".to_string())
             })
         }),
-        "invalid type: string \"a\", expected isize for key `foo.bar` at line 2 column 7",
-        "invalid type: string \"a\", expected isize for key `foo.bar`"
+        r#"TOML parse error at line 2, column 7
+  |
+2 | bar = "a"
+  |       ^^^
+invalid type: string "a", expected isize
+"#,
+        "invalid type: string \"a\", expected isize\n"
     }
 }
 
@@ -304,8 +314,13 @@ fn missing_errors() {
     error! {
         Foo,
         Table(map! { }),
-        "missing field `bar`",
-        "missing field `bar`"
+        r#"TOML parse error at line 1, column 1
+  |
+1 | 
+  | ^
+missing field `bar`
+"#,
+        "missing field `bar`\n"
     }
 }
 
diff --git a/crates/toml/tests/testsuite/spanned.rs b/crates/toml/tests/testsuite/spanned.rs
index 708e21b0..430dd5ba 100644
--- a/crates/toml/tests/testsuite/spanned.rs
+++ b/crates/toml/tests/testsuite/spanned.rs
@@ -1,3 +1,6 @@
+#![allow(renamed_and_removed_lints)]
+#![allow(clippy::blacklisted_name)]
+
 use std::collections::HashMap;
 use std::fmt::Debug;
 
@@ -34,9 +37,9 @@ fn test_spanned_field() {
         foo: T,
     }
 
-    fn good<'de, T>(s: &'de str, expected: &str, end: Option<usize>)
+    fn good<T>(s: &str, expected: &str, end: Option<usize>)
     where
-        T: serde::Deserialize<'de> + Debug + PartialEq,
+        T: serde::de::DeserializeOwned + Debug + PartialEq,
     {
         let foo: Foo<T> = toml::from_str(s).unwrap();
 
@@ -95,13 +98,7 @@ fn test_inner_spanned_table() {
 
         if zero {
             assert_eq!(foo.foo.span().start, 0);
-            // We'd actually have to assert equality with s.len() here,
-            // but the current implementation doesn't support that,
-            // and it's not possible with toml's data format to support it
-            // in the general case as spans aren't always well-defined.
-            // So this check mainly serves as a reminder that this test should
-            // be updated *if* one day there is support for emitting the actual span.
-            assert_eq!(foo.foo.span().end, 0);
+            assert_eq!(foo.foo.span().end, 73);
         } else {
             assert_eq!(foo.foo.span().start, s.find('{').unwrap());
             assert_eq!(foo.foo.span().end, s.find('}').unwrap() + 1);
@@ -113,7 +110,7 @@ fn test_inner_spanned_table() {
     }
 
     good(
-        "
+        "\
         [foo]
         a = 'b'
         bar = 'baz'
@@ -213,27 +210,7 @@ fn test_spanned_array() {
         foo: Vec<Spanned<HashMap<Spanned<String>, Spanned<String>>>>,
     }
 
-    fn good(s: &str) {
-        let foo_list: Foo = toml::from_str(s).unwrap();
-
-        for foo in foo_list.foo.iter() {
-            assert_eq!(foo.span().start, 0);
-            // We'd actually have to assert equality with s.len() here,
-            // but the current implementation doesn't support that,
-            // and it's not possible with toml's data format to support it
-            // in the general case as spans aren't always well-defined.
-            // So this check mainly serves as a reminder that this test should
-            // be updated *if* one day there is support for emitting the actual span.
-            assert_eq!(foo.span().end, 0);
-            for (k, v) in foo.as_ref().iter() {
-                assert_eq!(&s[k.span().start..k.span().end], k.as_ref());
-                assert_eq!(&s[(v.span().start + 1)..(v.span().end - 1)], v.as_ref());
-            }
-        }
-    }
-
-    good(
-        "
+    let toml = "\
         [[foo]]
         a = 'b'
         bar = 'baz'
@@ -244,6 +221,14 @@ fn test_spanned_array() {
         bar = 'baz'
         c = 'g'
         e = \"h\"
-    ",
-    );
+    ";
+    let foo_list: Foo = toml::from_str(toml).unwrap();
+
+    for (foo, expected) in foo_list.foo.iter().zip([0..75, 84..159]) {
+        assert_eq!(foo.span(), expected);
+        for (k, v) in foo.as_ref().iter() {
+            assert_eq!(&toml[k.span().start..k.span().end], k.as_ref());
+            assert_eq!(&toml[(v.span().start + 1)..(v.span().end - 1)], v.as_ref());
+        }
+    }
 }