use std::{collections::HashMap, fmt::Display};
#[derive(Debug, PartialEq, Clone)]
pub enum Value<'s> {
None,
Str(&'s str),
Int(i64),
Float(f64),
Bool(bool),
List(Vec<Value<'s>>),
Dict(HashMap<&'s str, Value<'s>>),
}
impl<'s> Value<'s> {
pub fn as_str(&self) -> Option<&'s str> {
match self {
Value::Str(s) => Some(s),
_ => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
Value::Int(i) => Some(*i),
_ => 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::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_list(&self) -> Option<&Vec<Value<'s>>> {
match self {
Value::List(l) => Some(l),
_ => None,
}
}
pub fn as_dict(&self) -> Option<&HashMap<&'s str, Value<'s>>> {
match self {
Value::Dict(d) => Some(d),
_ => None,
}
}
pub fn is_none(&self) -> bool {
matches!(self, Value::None)
}
pub fn is_str(&self) -> bool {
matches!(self, Value::Str(_))
}
pub fn is_int(&self) -> bool {
matches!(self, Value::Int(_))
}
pub fn is_float(&self) -> bool {
matches!(self, Value::Float(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
pub fn is_list(&self) -> bool {
matches!(self, Value::List(_))
}
pub fn is_dict(&self) -> bool {
matches!(self, Value::Dict(_))
}
pub fn len(&self) -> Option<usize> {
match self {
Value::List(l) => Some(l.len()),
Value::Dict(d) => Some(d.len()),
_ => None,
}
}
pub fn is_empty(&self) -> bool {
match self {
Value::List(l) => l.is_empty(),
Value::Dict(d) => d.is_empty(),
_ => false,
}
}
}
impl<'i, 's> std::ops::Index<&'i str> for Value<'s> {
type Output = Value<'s>;
fn index(&self, key: &'i str) -> &Self::Output {
match self {
Value::Dict(d) => d.get(key).unwrap_or(&Value::None),
_ => &Value::None,
}
}
}
impl<'s> std::ops::IndexMut<&'s str> for Value<'s> {
fn index_mut(&mut self, key: &'s str) -> &mut Self::Output {
match self {
Value::Dict(d) => d.entry(key).or_insert(Value::None),
_ => panic!("Cannot index non-dict value"),
}
}
}
impl<'s> std::ops::Index<usize> for Value<'s> {
type Output = Value<'s>;
fn index(&self, key: usize) -> &Self::Output {
match self {
Value::List(l) => l.get(key).unwrap_or(&Value::None),
_ => &Value::None,
}
}
}
impl<'s> std::ops::IndexMut<usize> for Value<'s> {
fn index_mut(&mut self, key: usize) -> &mut Self::Output {
match self {
Value::List(l) => match l.get_mut(key) {
Some(v) => v,
None => panic!("Index out of bounds"),
},
_ => panic!("Cannot index non-list value"),
}
}
}
impl<'s> Display for Value<'s> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::None => write!(f, "none"),
Value::Str(s) => write!(f, "{}", s),
Value::Int(i) => write!(f, "{}", i),
Value::Float(fl) => write!(f, "{}", fl),
Value::Bool(b) => write!(f, "{}", b),
Value::List(l) => {
write!(f, "[")?;
for v in l.iter() {
write!(f, " {}", v)?;
}
write!(f, " ]")
}
Value::Dict(d) => {
write!(f, "{{")?;
for (k, v) in d.iter() {
write!(f, " {}: {}", k, v)?;
}
write!(f, " }}")
}
}
}
}