#[cfg(feature = "value")]
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fmt;
use std::ops::{Index, IndexMut};
#[derive(Clone, PartialEq)]
pub enum Val {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<Val>),
Object(BTreeMap<String, Val>),
}
impl Val {
pub fn is_null(&self) -> bool { matches!(self, Val::Null) }
pub fn is_bool(&self) -> bool { matches!(self, Val::Bool(_)) }
pub fn is_number(&self) -> bool { matches!(self, Val::Number(_)) }
pub fn is_string(&self) -> bool { matches!(self, Val::String(_)) }
pub fn is_array(&self) -> bool { matches!(self, Val::Array(_)) }
pub fn is_object(&self) -> bool { matches!(self, Val::Object(_)) }
pub fn as_bool(&self) -> Option<bool> {
if let Val::Bool(b) = self { Some(*b) } else { None }
}
pub fn as_number(&self) -> Option<f64> {
if let Val::Number(n) = self { Some(*n) } else { None }
}
pub fn as_str(&self) -> Option<&str> {
if let Val::String(s) = self { Some(s) } else { None }
}
pub fn as_array(&self) -> Option<&[Val]> {
if let Val::Array(a) = self { Some(a) } else { None }
}
pub fn as_object(&self) -> Option<&BTreeMap<String, Val>> {
if let Val::Object(o) = self { Some(o) } else { None }
}
pub fn get(&self, key: &str) -> Option<&Val> {
self.as_object().and_then(|o| o.get(key))
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut Val> {
if let Val::Object(o) = self {
o.get_mut(key)
} else {
None
}
}
}
impl fmt::Debug for Val {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Val::Null => write!(f, "null"),
Val::Bool(b) => write!(f, "{}", b),
Val::Number(n) => write!(f, "{}", n),
Val::String(s) => write!(f, "\"{}\"", s),
Val::Array(a) => {
write!(f, "[")?;
for (i, v) in a.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{:?}", v)?;
}
write!(f, "]")
}
Val::Object(o) => {
write!(f, "{{")?;
for (i, (k, v)) in o.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "\"{}\": {:?}", k, v)?;
}
write!(f, "}}")
}
}
}
}
impl Index<&str> for Val {
type Output = Val;
fn index(&self, key: &str) -> &Self::Output {
self.get(key).unwrap_or(&Val::Null)
}
}
impl IndexMut<&str> for Val {
fn index_mut(&mut self, key: &str) -> &mut Self::Output {
if let Val::Object(o) = self {
o.entry(key.to_string()).or_insert(Val::Null)
} else {
panic!("Attempted to index into a non-object Val")
}
}
}
impl Index<usize> for Val {
type Output = Val;
fn index(&self, index: usize) -> &Self::Output {
if let Val::Array(a) = self {
a.get(index).unwrap_or(&Val::Null)
} else {
&Val::Null
}
}
}
impl IndexMut<usize> for Val {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if let Val::Array(a) = self {
if index >= a.len() {
a.resize(index + 1, Val::Null);
}
&mut a[index]
} else {
panic!("Attempted to index into a non-array Val")
}
}
}
impl From<bool> for Val {
fn from(b: bool) -> Self { Val::Bool(b) }
}
impl From<f64> for Val {
fn from(n: f64) -> Self { Val::Number(n) }
}
impl From<i64> for Val {
fn from(n: i64) -> Self { Val::Number(n as f64) }
}
impl From<i32> for Val {
fn from(n: i32) -> Self { Val::Number(n as f64) }
}
impl From<u64> for Val {
fn from(n: u64) -> Self { Val::Number(n as f64) }
}
impl From<u32> for Val {
fn from(n: u32) -> Self { Val::Number(n as f64) }
}
impl From<String> for Val {
fn from(s: String) -> Self { Val::String(s) }
}
impl From<&str> for Val {
fn from(s: &str) -> Self { Val::String(s.to_string()) }
}
impl<T: Into<Val>> From<Vec<T>> for Val {
fn from(v: Vec<T>) -> Self {
Val::Array(v.into_iter().map(Into::into).collect())
}
}
impl<T: Into<Val>, const N: usize> From<[T; N]> for Val {
fn from(arr: [T; N]) -> Self {
Val::Array(arr.into_iter().map(Into::into).collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_val_macro() {
}
}