1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! A Koto language module for working with JSON data

use {
    koto_runtime::{external_error, Value, ValueList, ValueMap, ValueVec},
    koto_serialize::SerializableValue,
    serde_json::Value as JsonValue,
};

fn json_value_to_koto_value(value: &serde_json::Value) -> Result<Value, String> {
    let result = match value {
        JsonValue::Null => Value::Empty,
        JsonValue::Bool(b) => Value::Bool(*b),
        JsonValue::Number(n) => match n.as_i64() {
            Some(n64) => Value::Number(n64.into()),
            None => match n.as_f64() {
                Some(n64) => Value::Number(n64.into()),
                None => return Err(format!("Number is out of range: {}", n)),
            },
        },
        JsonValue::String(s) => Value::Str(s.as_str().into()),
        JsonValue::Array(a) => {
            match a
                .iter()
                .map(|entry| json_value_to_koto_value(entry))
                .collect::<Result<ValueVec, String>>()
            {
                Ok(result) => Value::List(ValueList::with_data(result)),
                Err(e) => return Err(e),
            }
        }
        JsonValue::Object(o) => {
            let mut map = ValueMap::with_capacity(o.len());
            for (key, value) in o.iter() {
                map.add_value(key, json_value_to_koto_value(value)?);
            }
            Value::Map(map)
        }
    };

    Ok(result)
}

pub fn make_module() -> ValueMap {
    use Value::*;

    let mut result = ValueMap::new();

    result.add_fn("from_string", |vm, args| match vm.get_args(args) {
        [Str(s)] => match serde_json::from_str(&s) {
            Ok(value) => match json_value_to_koto_value(&value) {
                Ok(result) => Ok(result),
                Err(e) => external_error!("json.from_string: Error while parsing input: {}", e),
            },
            Err(e) => external_error!(
                "json.from_string: Error while parsing input: {}",
                e.to_string()
            ),
        },
        _ => external_error!("json.from_string expects a string as argument"),
    });

    result.add_fn("to_string", |vm, args| match vm.get_args(args) {
        [value] => match serde_json::to_string_pretty(&SerializableValue(value)) {
            Ok(result) => Ok(Str(result.into())),
            Err(e) => external_error!("json.to_string: {}", e),
        },
        _ => external_error!("json.to_string expects a single argument"),
    });

    result
}