mtots 0.1.2

The mtots scripting language
Documentation
//! dbin bindings -- for declaratively parsing binary files
//! Stil WIP...
use crate::Eval;
use crate::EvalResult;
use crate::Globals;
use crate::HMap;
use crate::NativeFunction;
use crate::Opaque;
use crate::RcStr;
use crate::Value;
use dbin::Data;
use dbin::Pattern;
use std::cell::Ref;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

pub const NAME: &str = "a._dbin";

pub(super) fn load(globals: &mut Globals) -> EvalResult<HMap<RcStr, Rc<RefCell<Value>>>> {
    let mut map = HashMap::<RcStr, Value>::new();

    for (key, val) in vec![
        ("U8", from_pattern_raw(Pattern::U8)),
        ("I8", from_pattern_raw(Pattern::I8)),
        ("LeU16", from_pattern_raw(Pattern::LeU16)),
        ("LeU32", from_pattern_raw(Pattern::LeU32)),
        ("LeU64", from_pattern_raw(Pattern::LeU64)),
        ("BeU16", from_pattern_raw(Pattern::BeU16)),
        ("BeU32", from_pattern_raw(Pattern::BeU32)),
        ("BeU64", from_pattern_raw(Pattern::BeU64)),
        ("LeI16", from_pattern_raw(Pattern::LeI16)),
        ("LeI32", from_pattern_raw(Pattern::LeI32)),
        ("LeI64", from_pattern_raw(Pattern::LeI64)),
        ("BeI16", from_pattern_raw(Pattern::BeI16)),
        ("BeI32", from_pattern_raw(Pattern::BeI32)),
        ("BeI64", from_pattern_raw(Pattern::BeI64)),
        ("LeF32", from_pattern_raw(Pattern::LeF32)),
        ("LeF64", from_pattern_raw(Pattern::LeF64)),
        ("BeF32", from_pattern_raw(Pattern::BeF32)),
        ("BeF64", from_pattern_raw(Pattern::BeF64)),
        ("CStr", from_pattern_raw(Pattern::CStr)),
    ] {
        map.insert(key.into(), val);
    }

    map.extend(
        vec![
            NativeFunction::new(
                "pattern_parse",
                &["pattern", "bytes"],
                |globals, args, _| {
                    let pattern = expect_pattern(globals, &args[0])?;
                    let bytes = Eval::expect_bytes(globals, &args[1])?;
                    let data = match pattern.parse(&bytes) {
                        Ok(data) => data,
                        Err(error) => return globals.set_exc_str(&format!("{:?}", error)),
                    };
                    Ok(translate_data(&data))
                },
            ),
            NativeFunction::new("new_pattern_exact", &["bytes"], |globals, args, _| {
                let bytes = Eval::expect_bytes_from_pattern(globals, &args[0])?;
                let pat = Pattern::Exact(bytes.into());
                Ok(from_pattern_raw(pat))
            }),
            NativeFunction::new(
                "new_pattern_array",
                &["pat", "f"],
                |globals, args, _| {
                    let bytes = Eval::expect_bytes_from_pattern(globals, &args[0])?;
                    let pat = Pattern::Exact(bytes.into());
                    Ok(from_pattern_raw(pat))
                },
            ),
        ]
        .into_iter()
        .map(|f| (f.name().clone(), f.into())),
    );

    Ok({
        let mut ret = HMap::new();
        for (key, value) in map {
            ret.insert(key, Rc::new(RefCell::new(value)));
        }
        ret
    })
}

fn from_pattern_raw(pattern: Pattern) -> Value {
    from_pattern(pattern.into())
}

fn from_pattern(pattern: Rc<Pattern>) -> Value {
    Opaque::new(pattern).into()
}

fn expect_pattern<'a>(globals: &mut Globals, value: &'a Value) -> EvalResult<Ref<'a, Rc<Pattern>>> {
    Eval::expect_opaque(globals, value)
}

fn translate_data(data: &Data) -> Value {
    match data {
        Data::Int(i) => Value::Int(*i),
        Data::Float(f) => Value::Float(*f),
        Data::Bytes(bytes) => Value::Bytes(bytes.clone()),
        Data::String(s) => Value::String(s.into()),
        Data::Seq(seq) => Value::List(Rc::new(seq.iter().map(translate_data).collect())),
    }
}