#![doc = include_str!("readme.md")]
use core::range::Range;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlRoot {
pub items: Vec<TomlItem>,
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TomlItem {
KeyValue(TomlKeyValue),
Table(TomlTable),
ArrayOfTables(TomlArrayOfTables),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlKeyValue {
pub key: TomlKey,
pub value: TomlValueNode,
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlTable {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub header: TomlTableHeader,
pub items: Vec<TomlKeyValue>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlTableHeader {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub key: TomlKey,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlArrayOfTables {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub header: TomlArrayOfTablesHeader,
pub items: Vec<TomlKeyValue>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlArrayOfTablesHeader {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub key: TomlKey,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlKey {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub segments: Vec<TomlKeySegment>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TomlKeySegment {
Bare(TomlBareKey),
Quoted(TomlQuotedKey),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlBareKey {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub name: String,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlQuotedKey {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: String,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TomlValueNode {
String(TomlString),
Integer(TomlInteger),
Float(TomlFloat),
Boolean(TomlBoolean),
DateTime(TomlDateTime),
Array(TomlArray),
InlineTable(TomlInlineTable),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlString {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: String,
pub is_multiline: bool,
pub is_literal: bool,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlInteger {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: i64,
pub format: IntegerFormat,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum IntegerFormat {
Decimal,
Hex,
Octal,
Binary,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlFloat {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: f64,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlBoolean {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: bool,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlDateTime {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub value: String,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlArray {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub items: Vec<TomlValueNode>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TomlInlineTable {
#[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
pub span: Range<usize>,
pub items: Vec<TomlKeyValue>,
}
impl TomlTable {
pub fn new(span: Range<usize>, header: TomlTableHeader) -> Self {
Self { span, header, items: Vec::new() }
}
pub fn get(&self, key: &str) -> Option<&TomlValueNode> {
for kv in &self.items {
if kv.key.to_string() == key {
return Some(&kv.value);
}
}
None
}
}
impl TomlKey {
pub fn to_string(&self) -> String {
self.segments
.iter()
.map(|s| match s {
TomlKeySegment::Bare(b) => b.name.clone(),
TomlKeySegment::Quoted(q) => q.value.clone(),
})
.collect::<Vec<_>>()
.join(".")
}
}
impl TomlValueNode {
pub fn as_str(&self) -> Option<&str> {
match self {
TomlValueNode::String(s) => Some(&s.value),
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
TomlValueNode::Integer(i) => Some(i.value),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
TomlValueNode::Boolean(b) => Some(b.value),
_ => None,
}
}
pub fn as_inline_table(&self) -> Option<&TomlInlineTable> {
match self {
TomlValueNode::InlineTable(t) => Some(t),
_ => None,
}
}
pub fn as_array(&self) -> Option<&TomlArray> {
match self {
TomlValueNode::Array(a) => Some(a),
_ => None,
}
}
pub fn span(&self) -> Range<usize> {
match self {
TomlValueNode::String(s) => s.span.clone(),
TomlValueNode::Integer(i) => i.span.clone(),
TomlValueNode::Float(f) => f.span.clone(),
TomlValueNode::Boolean(b) => b.span.clone(),
TomlValueNode::DateTime(dt) => dt.span.clone(),
TomlValueNode::Array(a) => a.span.clone(),
TomlValueNode::InlineTable(t) => t.span.clone(),
}
}
}
impl std::fmt::Display for TomlValueNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TomlValueNode::String(s) => write!(f, "\"{}\"", s.value),
TomlValueNode::Integer(i) => write!(f, "{}", i.value),
TomlValueNode::Float(fl) => write!(f, "{}", fl.value),
TomlValueNode::Boolean(b) => write!(f, "{}", b.value),
TomlValueNode::DateTime(dt) => write!(f, "{}", dt.value),
TomlValueNode::Array(a) => {
write!(f, "[")?;
for (i, item) in a.items.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
TomlValueNode::InlineTable(t) => {
write!(f, "{{")?;
for (i, item) in t.items.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{} = {}", item.key.to_string(), item.value)?;
}
write!(f, "}}")
}
}
}
}
impl TomlRoot {
pub fn into_value(self) -> TomlValueNode {
let mut items = Vec::new();
for item in self.items {
if let TomlItem::KeyValue(kv) = item {
items.push(kv);
}
}
TomlValueNode::InlineTable(TomlInlineTable { span: self.span, items })
}
}