use crate::{Item, Table};
pub mod parse_string {
use crate::error::Error;
use crate::{Context, Failed, Item};
pub fn from_toml<'de, T>(ctx: &mut Context<'de>, item: &Item<'de>) -> Result<T, Failed>
where
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
let Some(s) = item.as_str() else {
return Err(ctx.report_expected_but_found(&"a string", item));
};
match s.parse::<T>() {
Ok(val) => Ok(val),
Err(e) => Err(ctx.push_error(Error::custom(e, item.span()))),
}
}
}
#[cfg(feature = "to-toml")]
pub mod display {
use crate::{Arena, Item, ToTomlError};
pub fn to_toml<'a>(
value: &impl std::fmt::Display,
arena: &'a Arena,
) -> Result<Item<'a>, ToTomlError> {
let s = value.to_string();
Ok(Item::string(arena.alloc_str(&s)))
}
}
#[doc(hidden)]
pub struct ShallowTable<'de, 'b> {
table: Table<'de>,
__marker: std::marker::PhantomData<&'b Item<'de>>,
}
pub mod flatten_any {
use foldhash::HashMapExt;
#[cfg(feature = "to-toml")]
use crate::{Arena, ToToml, ToTomlError};
use crate::{
Context, Failed, FromToml, Item, Key, Table, error::MaybeTomlPath, helper::ShallowTable,
parser::KeyRef,
};
fn patch_errors<'de, 'b>(
ctx: &mut Context<'de>,
original: usize,
parent: &Table<'de>,
partial: &ShallowTable<'de, 'b>,
) {
let entries = partial.table.entries();
let entry_size = std::mem::size_of::<(Key<'_>, Item<'_>)>();
let base = entries.as_ptr() as *const u8;
let end = unsafe { base.add(entries.len() * entry_size) };
let mut temporary_index: foldhash::HashMap<KeyRef<'de>, usize>;
let errors = &mut ctx.errors[original..];
let index = if parent.span().is_empty() {
if parent.len() > 8 && errors.len() > 2 {
temporary_index = foldhash::HashMap::with_capacity(parent.len());
let table_id = unsafe { parent.value.first_key_span_start_unchecked() };
let mut i = 0;
for (key, _) in parent.entries() {
temporary_index.insert(KeyRef::new(key.name, table_id), i);
i += 1;
}
Some(&temporary_index)
} else {
None
}
} else {
Some(&ctx.index)
};
for error in errors {
if !error.path.is_uncomputed() {
continue;
}
if std::ptr::addr_eq(error.path.uncomputed_ptr(), partial) {
error.path = MaybeTomlPath::uncomputed(parent.as_item());
error.span = parent.span();
continue;
}
let ptr = error.path.uncomputed_ptr() as *const u8;
if ptr < base || ptr >= end {
continue;
}
let byte_offset = unsafe { ptr.byte_offset_from(base) } as usize;
let entry_index = byte_offset / entry_size;
if let Some((key, _)) = &entries.get(entry_index) {
if let Some((_, item)) = parent.value.get_entry_with_maybe_index(key.name, index) {
error.path = MaybeTomlPath::uncomputed(item);
}
}
}
}
pub fn init<'a, 'b>() -> ShallowTable<'a, 'b> {
ShallowTable {
table: Table::new(),
__marker: std::marker::PhantomData,
}
}
pub fn insert<'de, 'b>(
ctx: &mut Context<'de>,
key: &Key<'de>,
item: &'b Item<'de>,
partial: &mut ShallowTable<'de, 'b>,
) -> Result<(), Failed> {
let shallow = unsafe { std::ptr::read(item) };
partial.table.insert_unique(*key, shallow, ctx.arena);
Ok(())
}
pub fn finish<'de, 'b, T: FromToml<'de>>(
ctx: &mut Context<'de>,
parent: &Table<'de>,
partial: ShallowTable<'de, 'b>,
) -> Result<T, Failed> {
let original = ctx.errors.len();
let result = T::from_toml(ctx, partial.table.as_item());
if ctx.errors.len() > original {
patch_errors(ctx, original, parent, &partial);
}
result
}
#[cfg(feature = "to-toml")]
pub fn to_flattened<'a, T: ToToml>(
value: &'a T,
arena: &'a Arena,
table: &mut Table<'a>,
) -> Result<(), ToTomlError> {
let item = value.to_toml(arena)?;
let Some(src) = item.into_table() else {
return Err(ToTomlError::from("flatten_any: expected a table"));
};
for (key, val) in src {
table.insert_unique(key, val, arena);
}
Ok(())
}
}