use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
Unit,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Map(BTreeMap<String, Value>),
List(Vec<Value>),
Symbol(String),
}
impl Value {
pub fn is_unit(&self) -> bool {
matches!(self, Value::Unit)
}
pub fn from_argument_text(s: &str) -> Self {
if let Ok(b) = s.parse::<bool>() {
return Value::Bool(b);
}
if let Ok(i) = s.parse::<i64>() {
return Value::Int(i);
}
if let Ok(f) = s.parse::<f64>() {
return Value::Float(f);
}
Value::Symbol(s.to_string())
}
pub fn render(&self) -> String {
match self {
Value::Unit => "()".to_string(),
Value::Bool(b) => b.to_string(),
Value::Int(i) => i.to_string(),
Value::Float(f) => f.to_string(),
Value::String(s) => format!("{s:?}"),
Value::List(items) => {
let parts: Vec<String> = items.iter().map(|v| v.render()).collect();
format!("[{}]", parts.join(", "))
}
Value::Map(m) => {
let parts: Vec<String> =
m.iter().map(|(k, v)| format!("{k}: {}", v.render())).collect();
format!("{{{}}}", parts.join(", "))
}
Value::Symbol(s) => s.clone(),
}
}
}
impl Default for Value {
fn default() -> Self {
Value::Unit
}
}