guartcl 0.5.0-beta1

Enhanced Jim Tcl.
Documentation
//! typedata conversion commands

use std::{
    borrow::Cow,
    fs::{File, read_to_string},
};

use jimtcl::{Interp, JimError, JimObject, JimResult, check_or_error, custom::JimExtensionType};

use super::TypedData;

/// Convert a TypeData structure to native Tcl lists, dicts, and values.
pub fn td_native<'jim>(interp: &'jim Interp, obj: &JimObject<'jim>) -> JimResult<JimObject<'jim>> {
    let data = TypedData::extract_ref(obj)?;
    data.to_native(interp)
}

/// Parse JSON into a Typed Data structure.
pub fn td_parse_json<'jim>(
    _interp: &'jim Interp,
    args: &[JimObject<'jim>],
) -> JimResult<TypedData> {
    let usage = "usage: parse json ?-file? <input>";
    check_or_error!(args.len() >= 2, usage);
    if args[1].as_str()? == "-file" {
        check_or_error!(args.len() == 3, usage);
        let file = File::open(args[2].as_str()?)?;
        serde_json::from_reader(file).map_err(JimError::wrap)
    } else {
        check_or_error!(args.len() == 2, usage);
        let data = TypedData::extract_ref(&args[1])?;
        // FIXME speed this up by not cloning
        Ok(data.clone())
    }
}

/// Parse TOML into a Typed Data structure.
pub fn td_parse_toml<'jim>(
    _interp: &'jim Interp,
    args: &[JimObject<'jim>],
) -> JimResult<TypedData> {
    let usage = "usage: td parse toml ?-file? <input>";
    check_or_error!(args.len() >= 2, usage);
    let data: Cow<'_, str> = if args[1].as_str()? == "-file" {
        check_or_error!(args.len() == 3, usage);
        read_to_string(args[2].as_str()?)?.into()
    } else {
        check_or_error!(args.len() == 2, usage);
        args[1].as_str()?.into()
    };

    let data = toml::from_str(&data).map_err(JimError::wrap)?;
    Ok(data)
}

/// Parse YAML into a Typed Data structure.
pub fn td_parse_yaml<'jim>(
    _interp: &'jim Interp,
    args: &[JimObject<'jim>],
) -> JimResult<TypedData> {
    let usage = "usage: td parse yaml ?-file? <input>";
    check_or_error!(args.len() >= 2, usage);
    let res = if args[1].as_str()? == "-file" {
        check_or_error!(args.len() == 3, usage);
        let open = File::open(args[2].as_str()?)?;
        yaml_serde::from_reader(open)
    } else {
        check_or_error!(args.len() == 2, usage);
        let data = args[1].as_bytes();
        yaml_serde::from_slice(&data)
    };

    res.map_err(JimError::wrap)
}