use std::rc::Rc;
use indexmap::IndexMap;
use jimtcl::{
Interp, JimObject, JimResult,
custom::{JimExtensionData, JimExtensionType},
object::IntoJimObj,
};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum TypedData {
Null,
Bool(bool),
Int(i64),
Float(f64),
Str(String),
List(Rc<Vec<Rc<TypedData>>>),
Record(Rc<IndexMap<String, Rc<TypedData>>>),
}
impl TypedData {
pub fn is_null(&self) -> bool {
matches!(self, TypedData::Null)
}
pub fn to_native<'jim>(&self, interp: &'jim Interp) -> JimResult<JimObject<'jim>> {
match self {
TypedData::Null => Ok(JimObject::empty(interp)),
TypedData::Bool(true) => Ok(1i32.to_jim(interp)),
TypedData::Bool(false) => Ok(0i32.to_jim(interp)),
TypedData::Int(n) => Ok(n.to_jim(interp)),
TypedData::Float(x) => Ok(x.to_jim(interp)),
TypedData::Str(s) => Ok(s.as_str().to_jim(interp)),
TypedData::List(contents) => {
let out = JimObject::empty(interp);
for x in contents.iter() {
out.list_append(x.to_native(interp)?);
}
Ok(out)
}
TypedData::Record(contents) => {
let out = JimObject::empty(interp);
for (k, v) in contents.iter() {
out.dict_set_obj(k.as_str().to_jim(interp), v.to_native(interp)?)?;
}
Ok(out)
}
}
}
}
impl JimExtensionData for TypedData {
fn to_tcl_string(&self) -> String {
serde_json::to_string(self).unwrap_or_else(|_| "!!UNREPRESENTABLE".to_owned())
}
}
impl JimExtensionType for TypedData {
fn parse_tcl_string(repr: &str) -> jimtcl::JimResult<Self> {
serde_json::from_str(repr).map_err(|e| format!("JSON parse failure: {}", e).into())
}
}