Skip to main content

toml_spanner/
lib.rs

1//! A high-performance TOML parser that preserves span information for every
2//! parsed value.
3//!
4//! Strings are zero-copy where possible, borrowing directly from the input;
5//! escape sequences are allocated into a caller-supplied [`Arena`].
6//!
7//! # Quick start
8//!
9//! Call [`parse`] with a TOML string and an [`Arena`] to get a [`Table`]. Then
10//! extract values with [`Table::required`] and [`Table::optional`], or index
11//! into nested structures with bracket operators that return [`MaybeItem`]
12//! (never panic on missing keys).
13//!
14//! # Examples
15//!
16//! ```
17//! use toml_spanner::{Arena, Deserialize, Error, Item};
18//!
19//! #[derive(Debug)]
20//! struct Things {
21//!     name: String,
22//!     value: u32,
23//!     color: Option<String>,
24//! }
25//!
26//! impl<'de> Deserialize<'de> for Things {
27//!     fn deserialize(value: &mut Item<'de>) -> Result<Self, Error> {
28//!         let table = value.expect_table()?;
29//!         Ok(Things {
30//!             name: table.required("name")?,
31//!             value: table.required("value")?,
32//!             color: table.optional("color")?,
33//!         })
34//!     }
35//! }
36//!
37//! let content = r#"
38//! dev-mode = true
39//!
40//! [[things]]
41//! name = "hammer"
42//! value = 43
43//!
44//! [[things]]
45//! name = "drill"
46//! value = 300
47//! color = "green"
48//! "#;
49//!
50//! let arena = Arena::new();
51//! let mut table = toml_spanner::parse(content, &arena)?;
52//!
53//! // Null-coalescing index operators — missing keys return a None-like
54//! // MaybeItem instead of panicking.
55//! assert_eq!(table["things"][0]["color"].as_str(), None);
56//! assert_eq!(table["things"][1]["color"].as_str(), Some("green"));
57//!
58//! // Deserialize typed values out of the table.
59//! let things: Vec<Things> = table.required("things")?;
60//! let dev_mode: bool = table.optional("dev-mode")?.unwrap_or(false);
61//! // Error if unconsumed fields remain.
62//! table.expect_empty()?;
63//!
64//! assert_eq!(things.len(), 2);
65//! assert_eq!(things[0].name, "hammer");
66//! assert!(dev_mode);
67//! # Ok::<(), Error>(())
68//! ```
69
70mod arena;
71mod array;
72mod de;
73mod error;
74mod parser;
75mod span;
76mod table;
77mod value;
78
79pub use arena::Arena;
80pub use array::Array;
81pub use error::{Error, ErrorKind};
82pub use parser::parse;
83pub use span::{Span, Spanned};
84pub use table::Table;
85pub use value::{Item, Key, MaybeItem, Value, ValueMut};
86
87#[cfg(feature = "serde")]
88pub mod impl_serde;
89
90/// Converts a parsed TOML [`Item`] into a typed Rust value.
91///
92/// Implement this trait on your own types to extract them from a parsed TOML
93/// document via [`Table::required`] and [`Table::optional`].
94///
95/// Built-in implementations are provided for common types: [`bool`], integer
96/// types ([`i8`] through [`i64`], [`u8`] through [`u64`], [`usize`]),
97/// floating-point types ([`f32`], [`f64`]), [`String`],
98/// [`Cow<'de, str>`](std::borrow::Cow), [`Str`], [`Vec<T>`], and
99/// [`Spanned<T>`].
100///
101/// # Examples
102///
103/// ```
104/// use toml_spanner::{Deserialize, Error, Item};
105///
106/// struct Endpoint {
107///     host: String,
108///     port: u16,
109/// }
110///
111/// impl<'de> Deserialize<'de> for Endpoint {
112///     fn deserialize(item: &mut Item<'de>) -> Result<Self, Error> {
113///         let table = item.expect_table()?;
114///         Ok(Endpoint {
115///             host: table.required("host")?,
116///             port: table.required("port")?,
117///         })
118///     }
119/// }
120/// ```
121pub trait Deserialize<'de>: Sized {
122    /// Deserializes `Self` from the given [`Item`], returning an error on failure.
123    fn deserialize(item: &mut Item<'de>) -> Result<Self, Error>;
124}
125
126/// Object-safe version of [`Deserialize`] for types that do not borrow from
127/// the input.
128///
129/// Automatically implemented for every `T: for<'de> Deserialize<'de>`.
130pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
131impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}