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 str;
77mod table;
78mod value;
79
80pub use arena::Arena;
81pub use array::Array;
82pub use error::{Error, ErrorKind};
83pub use parser::parse;
84pub use span::{Span, Spanned};
85pub use str::Str;
86pub use table::Table;
87pub use value::{Item, Key, MaybeItem, Value, ValueMut};
88
89#[cfg(feature = "serde")]
90pub mod impl_serde;
91
92/// Converts a parsed TOML [`Item`] into a typed Rust value.
93///
94/// Implement this trait on your own types to extract them from a parsed TOML
95/// document via [`Table::required`] and [`Table::optional`].
96///
97/// Built-in implementations are provided for common types: [`bool`], integer
98/// types ([`i8`] through [`i64`], [`u8`] through [`u64`], [`usize`]),
99/// floating-point types ([`f32`], [`f64`]), [`String`],
100/// [`Cow<'de, str>`](std::borrow::Cow), [`Str`], [`Vec<T>`], and
101/// [`Spanned<T>`].
102///
103/// # Examples
104///
105/// ```
106/// use toml_spanner::{Deserialize, Error, Item};
107///
108/// struct Endpoint {
109///     host: String,
110///     port: u16,
111/// }
112///
113/// impl<'de> Deserialize<'de> for Endpoint {
114///     fn deserialize(item: &mut Item<'de>) -> Result<Self, Error> {
115///         let table = item.expect_table()?;
116///         Ok(Endpoint {
117///             host: table.required("host")?,
118///             port: table.required("port")?,
119///         })
120///     }
121/// }
122/// ```
123pub trait Deserialize<'de>: Sized {
124    /// Deserializes `Self` from the given [`Item`], returning an error on failure.
125    fn deserialize(item: &mut Item<'de>) -> Result<Self, Error>;
126}
127
128/// Object-safe version of [`Deserialize`] for types that do not borrow from
129/// the input.
130///
131/// Automatically implemented for every `T: for<'de> Deserialize<'de>`.
132pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
133impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}