use std::str::FromStr;
use toml_datetime::*;
use crate::array_of_tables::ArrayOfTables;
use crate::table::TableLike;
use crate::{Array, InlineTable, Table, Value};
#[derive(Debug, Clone)]
pub enum Item {
None,
Value(Value),
Table(Table),
ArrayOfTables(ArrayOfTables),
}
impl Item {
pub fn or_insert(&mut self, item: Item) -> &mut Item {
if self.is_none() {
*self = item
}
self
}
}
impl Item {
pub fn type_name(&self) -> &'static str {
match self {
Item::None => "none",
Item::Value(v) => v.type_name(),
Item::Table(..) => "table",
Item::ArrayOfTables(..) => "array of tables",
}
}
pub fn get<I: crate::index::Index>(&self, index: I) -> Option<&Item> {
index.index(self)
}
pub fn get_mut<I: crate::index::Index>(&mut self, index: I) -> Option<&mut Item> {
index.index_mut(self)
}
pub fn as_value(&self) -> Option<&Value> {
match *self {
Item::Value(ref v) => Some(v),
_ => None,
}
}
pub fn as_table(&self) -> Option<&Table> {
match *self {
Item::Table(ref t) => Some(t),
_ => None,
}
}
pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> {
match *self {
Item::ArrayOfTables(ref a) => Some(a),
_ => None,
}
}
pub fn as_value_mut(&mut self) -> Option<&mut Value> {
match *self {
Item::Value(ref mut v) => Some(v),
_ => None,
}
}
pub fn as_table_mut(&mut self) -> Option<&mut Table> {
match *self {
Item::Table(ref mut t) => Some(t),
_ => None,
}
}
pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> {
match *self {
Item::ArrayOfTables(ref mut a) => Some(a),
_ => None,
}
}
pub fn into_value(self) -> Result<Value, Self> {
match self {
Item::None => Err(self),
Item::Value(v) => Ok(v),
Item::Table(v) => {
let v = v.into_inline_table();
Ok(Value::InlineTable(v))
}
Item::ArrayOfTables(v) => {
let v = v.into_array();
Ok(Value::Array(v))
}
}
}
pub fn make_value(&mut self) {
let other = std::mem::take(self);
let other = other.into_value().map(Item::Value).unwrap_or(Item::None);
*self = other;
}
pub fn into_table(self) -> Result<Table, Self> {
match self {
Item::Table(t) => Ok(t),
Item::Value(Value::InlineTable(t)) => Ok(t.into_table()),
_ => Err(self),
}
}
pub fn into_array_of_tables(self) -> Result<ArrayOfTables, Self> {
match self {
Item::ArrayOfTables(a) => Ok(a),
Item::Value(Value::Array(a)) => {
if a.is_empty() {
Err(Item::Value(Value::Array(a)))
} else if a.iter().all(|v| v.is_inline_table()) {
let mut aot = ArrayOfTables::new();
aot.values = a.values;
for value in aot.values.iter_mut() {
value.make_item();
}
Ok(aot)
} else {
Err(Item::Value(Value::Array(a)))
}
}
_ => Err(self),
}
}
pub(crate) fn make_item(&mut self) {
let other = std::mem::take(self);
let other = match other.into_table().map(crate::Item::Table) {
Ok(i) => i,
Err(i) => i,
};
let other = match other.into_array_of_tables().map(crate::Item::ArrayOfTables) {
Ok(i) => i,
Err(i) => i,
};
*self = other;
}
pub fn is_value(&self) -> bool {
self.as_value().is_some()
}
pub fn is_table(&self) -> bool {
self.as_table().is_some()
}
pub fn is_array_of_tables(&self) -> bool {
self.as_array_of_tables().is_some()
}
pub fn is_none(&self) -> bool {
matches!(*self, Item::None)
}
pub fn as_integer(&self) -> Option<i64> {
self.as_value().and_then(Value::as_integer)
}
pub fn is_integer(&self) -> bool {
self.as_integer().is_some()
}
pub fn as_float(&self) -> Option<f64> {
self.as_value().and_then(Value::as_float)
}
pub fn is_float(&self) -> bool {
self.as_float().is_some()
}
pub fn as_bool(&self) -> Option<bool> {
self.as_value().and_then(Value::as_bool)
}
pub fn is_bool(&self) -> bool {
self.as_bool().is_some()
}
pub fn as_str(&self) -> Option<&str> {
self.as_value().and_then(Value::as_str)
}
pub fn is_str(&self) -> bool {
self.as_str().is_some()
}
pub fn as_datetime(&self) -> Option<&Datetime> {
self.as_value().and_then(Value::as_datetime)
}
pub fn is_datetime(&self) -> bool {
self.as_datetime().is_some()
}
pub fn as_array(&self) -> Option<&Array> {
self.as_value().and_then(Value::as_array)
}
pub fn as_array_mut(&mut self) -> Option<&mut Array> {
self.as_value_mut().and_then(Value::as_array_mut)
}
pub fn is_array(&self) -> bool {
self.as_array().is_some()
}
pub fn as_inline_table(&self) -> Option<&InlineTable> {
self.as_value().and_then(Value::as_inline_table)
}
pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> {
self.as_value_mut().and_then(Value::as_inline_table_mut)
}
pub fn is_inline_table(&self) -> bool {
self.as_inline_table().is_some()
}
pub fn as_table_like(&self) -> Option<&dyn TableLike> {
self.as_table()
.map(|t| t as &dyn TableLike)
.or_else(|| self.as_inline_table().map(|t| t as &dyn TableLike))
}
pub fn as_table_like_mut(&mut self) -> Option<&mut dyn TableLike> {
match self {
Item::Table(t) => Some(t as &mut dyn TableLike),
Item::Value(Value::InlineTable(t)) => Some(t as &mut dyn TableLike),
_ => None,
}
}
pub fn is_table_like(&self) -> bool {
self.as_table_like().is_some()
}
}
impl Default for Item {
fn default() -> Self {
Item::None
}
}
impl FromStr for Item {
type Err = crate::TomlError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = s.parse::<Value>()?;
Ok(Item::Value(value))
}
}
impl std::fmt::Display for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Item::None => Ok(()),
Item::Value(v) => v.fmt(f),
Item::Table(v) => v.fmt(f),
Item::ArrayOfTables(v) => v.fmt(f),
}
}
}
pub fn value<V: Into<Value>>(v: V) -> Item {
Item::Value(v.into())
}
pub fn table() -> Item {
Item::Table(Table::new())
}
pub fn array() -> Item {
Item::ArrayOfTables(ArrayOfTables::new())
}