boml 2.0.0

A dead-simple, efficient, dependency-free TOML parser for Rust.
Documentation
//! Parses bare and quoted keys.

use {
	crate::{
		TomlError, TomlErrorKind,
		table::TomlTable,
		text::{CowSpan, Text},
		types::TomlValue,
	},
	std::{collections::hash_map::Entry, hint::unreachable_unchecked},
};

const VALID_BARE_KEY_CHARS: &[u8] =
	b"ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz_0123456789";

pub fn parse_key<'a>(text: &mut Text<'a>) -> Result<CowSpan<'a>, TomlError<'a>> {
	if text.current_byte() == Some(b'\'') {
		return crate::parser::string::parse_literal_string(text).map(CowSpan::Raw);
	} else if text.current_byte() == Some(b'"') {
		return crate::parser::string::parse_basic_string(text);
	}

	let start = text.idx();
	while text
		.current_byte()
		.map(|byte| VALID_BARE_KEY_CHARS.contains(&byte))
		== Some(true)
	{
		text.next();
	}

	if text.idx() == start {
		return Err(TomlError {
			src: text.absolute_excerpt(start..=start),
			kind: TomlErrorKind::NoKeyInAssignment,
		});
	}

	let key = text.absolute_excerpt(start..text.idx());
	Ok(CowSpan::Raw(key))
}

/// Parses a potentially nested key (i.e. a key that has dots, such as `table.subtable`).
pub fn parse_nested<'a, 't>(
	text: &mut Text<'a>,
	mut root: &'t mut TomlTable<'a>,
) -> Result<(&'t mut TomlTable<'a>, CowSpan<'a>), TomlError<'a>> {
	let start = text.idx();

	loop {
		let key = parse_key(text)?;
		text.skip_whitespace();

		if text.current_byte() != Some(b'.') {
			return Ok((root, key));
		}
		text.next();
		text.skip_whitespace();

		let entry = root.map.entry(key);

		if let Entry::Occupied(entry) = entry {
			root = match entry.into_mut() {
				TomlValue::Table(table) => table,
				TomlValue::Array(array) if array.is_array_of_tables => {
					let Some(TomlValue::Table(table)) = array.last_mut() else {
						unreachable!()
					};
					table
				}
				_ => {
					return Err(TomlError {
						src: text.absolute_excerpt(start..text.idx() - 2),
						kind: TomlErrorKind::ReusedKey,
					});
				}
			};
		} else {
			let Entry::Vacant(entry) = entry else {
				unsafe { unreachable_unchecked() }
			};
			let TomlValue::Table(table) = entry.insert(TomlValue::Table(TomlTable::default()))
			else {
				unsafe { unreachable_unchecked() }
			};
			root = table;
		}
	}
}