// TT-muncher to parse TOML syntax into a toml::Value. // // @toplevel -- Parse tokens outside of an inline table or inline array. In // this state, `[table headers]` and `[[array headers]]` are // allowed and `key = value` pairs are not separated by commas. // // @topleveldatetime -- Helper to parse a Datetime from string and insert it // into a table, continuing in the @toplevel state. // // @path -- Turn a path segment into a string. Segments that look like idents // are stringified, while quoted segments like `"cfg(windows)"` // are not. // // @value -- Parse the value part of a `key = value` pair, which may be a // primitive or inline table or inline array. // // @table -- Parse the contents of an inline table, returning them as a // toml::Value::Table. // // @tabledatetime -- Helper to parse a Datetime from string and insert it // into a table, continuing in the @table state. // // @array -- Parse the contents of an inline array, returning them as a // toml::Value::Array. // // @arraydatetime -- Helper to parse a Datetime from string and push it into // an array, continuing in the @array state. // // @trailingcomma -- Helper to append a comma to a sequence of tokens if the // sequence is non-empty and does not already end in a trailing // comma. // #[macro_export] #[doc(hidden)]
macro_rules! toml_internal { // Base case, no elements remaining.
(@toplevel $root:ident [$($path:tt)*]) => {};
// Turn a path segment into a string.
(@path $ident:ident) => {
stringify!($ident)
};
// For a path segment that is not an ident, expect that it is already a // quoted string, like in `[target."cfg(windows)".dependencies]`.
(@path $quoted:tt) => {
$quoted
};
// Construct a Value from an inline table.
(@value { $($inline:tt)* }) => {{ letmut table = $crate::Value::Table($crate::value::Table::new());
$crate::toml_internal!(@trailingcomma (@table table) $($inline)*);
table
}};
// Construct a Value from an inline array.
(@value [ $($inline:tt)* ]) => {{ letmut array = $crate::value::Array::new();
$crate::toml_internal!(@trailingcomma (@array array) $($inline)*);
$crate::Value::Array(array)
}};
// Construct a Value from any other type, probably string or boolean or number.
(@value $v:tt) => {{ // TODO: Implement this with something like serde_json::to_value instead. let de = $crate::macros::IntoDeserializer::<$crate::de::Error>::into_deserializer($v);
<$crate::Value as $crate::macros::Deserialize>::deserialize(de).unwrap()
}};
// Base case of inline table.
(@table $root:ident) => {};
// Parse any other type, probably string or boolean or number.
(@array $root:ident $v:tt , $($rest:tt)*) => {
$root.push($crate::toml_internal!(@value $v));
$crate::toml_internal!(@array $root $($rest)*);
};
// Parse a Datetime from string and continue in @array state.
(@arraydatetime $root:ident ($($datetime:tt)*) $($rest:tt)*) => {
$root.push($crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
$crate::toml_internal!(@array $root $($rest)*);
};
// No trailing comma required if the tokens are empty.
(@trailingcomma ($($args:tt)*)) => {
$crate::toml_internal!($($args)*);
};
// Tokens end with a trailing comma, do not append another one.
(@trailingcomma ($($args:tt)*) ,) => {
$crate::toml_internal!($($args)* ,);
};
// Tokens end with something other than comma, append a trailing comma.
(@trailingcomma ($($args:tt)*) $last:tt) => {
$crate::toml_internal!($($args)* $last ,);
};
// Not yet at the last token.
(@trailingcomma ($($args:tt)*) $first:tt $($rest:tt)+) => {
$crate::toml_internal!(@trailingcomma ($($args)* $first) $($rest)+);
};
}
// Called when parsing a `key = value` pair. // Inserts an entry into the table at the given path. pubfn insert_toml(root: &mut Value, path: &[&str], value: Value) {
*traverse(root, path) = value;
}
// Called when parsing an `[[array header]]`. // Pushes an empty table onto the array at the given path. pubfn push_toml(root: &mut Value, path: &[&str]) { let target = traverse(root, path); if !target.is_array() {
*target = Value::Array(Array::new());
}
target
.as_array_mut()
.unwrap()
.push(Value::Table(Table::new()));
}
fn traverse<'a>(root: &'a mut Value, path: &[&str]) -> &'a mut Value { letmut cur = root; for &key in path { // Lexical lifetimes :D let cur1 = cur;
// From the TOML spec: // // > Each double-bracketed sub-table will belong to the most recently // > defined table element above it. let cur2 = if cur1.is_array() {
cur1.as_array_mut().unwrap().last_mut().unwrap()
} else {
cur1
};
// We are about to index into this value, so it better be a table. if !cur2.is_table() {
*cur2 = Value::Table(Table::new());
}
if !cur2.as_table().unwrap().contains_key(key) { // Insert an empty table for the next loop iteration to point to. let empty = Value::Table(Table::new());
cur2.as_table_mut().unwrap().insert(key.to_owned(), empty);
}
// Step into the current table.
cur = cur2.as_table_mut().unwrap().get_mut(key).unwrap();
}
cur
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.