use alloc::borrow::ToOwned;
use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::ops::Index;
use core::str::FromStr;
use crate::Error;
use crate::datetime::Datetime;
pub type Table = BTreeMap<String, Value>;
pub type Array = Vec<Value>;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
String(String),
Integer(i64),
Float(f64),
Boolean(bool),
Datetime(Datetime),
Array(Array),
Table(Table),
}
impl Value {
pub fn is_str(&self) -> bool {
matches!(self, Value::String(_))
}
pub fn is_integer(&self) -> bool {
matches!(self, Value::Integer(_))
}
pub fn is_float(&self) -> bool {
matches!(self, Value::Float(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Boolean(_))
}
pub fn is_datetime(&self) -> bool {
matches!(self, Value::Datetime(_))
}
pub fn is_array(&self) -> bool {
matches!(self, Value::Array(_))
}
pub fn is_table(&self) -> bool {
matches!(self, Value::Table(_))
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
Value::Integer(n) => Some(*n),
_ => None,
}
}
pub fn as_float(&self) -> Option<f64> {
match self {
Value::Float(f) => Some(*f),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Boolean(b) => Some(*b),
_ => None,
}
}
pub fn as_datetime(&self) -> Option<&Datetime> {
match self {
Value::Datetime(dt) => Some(dt),
_ => None,
}
}
pub fn as_array(&self) -> Option<&Array> {
match self {
Value::Array(arr) => Some(arr),
_ => None,
}
}
pub fn as_array_mut(&mut self) -> Option<&mut Array> {
match self {
Value::Array(arr) => Some(arr),
_ => None,
}
}
pub fn as_table(&self) -> Option<&Table> {
match self {
Value::Table(t) => Some(t),
_ => None,
}
}
pub fn as_table_mut(&mut self) -> Option<&mut Table> {
match self {
Value::Table(t) => Some(t),
_ => None,
}
}
pub fn type_name(&self) -> &'static str {
match self {
Value::String(_) => "string",
Value::Integer(_) => "integer",
Value::Float(_) => "float",
Value::Boolean(_) => "boolean",
Value::Datetime(_) => "datetime",
Value::Array(_) => "array",
Value::Table(_) => "table",
}
}
pub fn get(&self, key: &str) -> Option<&Value> {
self.as_table()?.get(key)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
self.as_table_mut()?.get_mut(key)
}
}
impl Index<&str> for Value {
type Output = Value;
fn index(&self, key: &str) -> &Value {
self.get(key)
.unwrap_or_else(|| panic!("key '{key}' not found"))
}
}
impl Index<usize> for Value {
type Output = Value;
fn index(&self, index: usize) -> &Value {
match self {
Value::Array(arr) => &arr[index],
_ => panic!("index access on non-array value"),
}
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Value::String(s)
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Value::String(s.to_owned())
}
}
impl From<i64> for Value {
fn from(n: i64) -> Self {
Value::Integer(n)
}
}
impl From<i32> for Value {
fn from(n: i32) -> Self {
Value::Integer(i64::from(n))
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Value::Float(f)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Value::Boolean(b)
}
}
impl From<Datetime> for Value {
fn from(dt: Datetime) -> Self {
Value::Datetime(dt)
}
}
impl From<Array> for Value {
fn from(arr: Array) -> Self {
Value::Array(arr)
}
}
impl From<Table> for Value {
fn from(t: Table) -> Self {
Value::Table(t)
}
}
impl FromStr for Value {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::from_str(s).map(Value::Table)
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match crate::to_string(self) {
Ok(s) => f.write_str(&s),
Err(_) => Err(fmt::Error),
}
}
}