guartcl 0.5.0-beta4

Enhanced Jim Tcl.
Documentation
use std::rc::Rc;

use indexmap::IndexMap;
use jimtcl::{
    Interp, JimObject, JimResult,
    custom::{JimExtensionData, JimExtensionType},
    object::IntoJimObj,
};
use serde::{Deserialize, Serialize};

/// Structure for JSON-like typed data.
#[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 {
    /// Query if this typed data is `null`.
    pub fn is_null(&self) -> bool {
        matches!(self, TypedData::Null)
    }

    /// Convert this structure to native Tcl lists, dicts, and values.
    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())
    }
}