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
use crate::utils::result::ResultExt;
use rquickjs::{Array, Ctx, IntoJs, Null, Object, Result, Undefined, Value};
use simd_json::{Node, StaticNode};

pub fn json_parse<'js, T: Into<Vec<u8>>>(ctx: &Ctx<'js>, json: T) -> Result<Value<'js>> {
    let mut json: Vec<u8> = json.into();
    let tape = simd_json::to_tape(&mut json).or_throw(ctx)?;
    let tape = tape.0;

    if let Some(first) = tape.first() {
        return match first {
            Node::String(value) => value.into_js(ctx),
            Node::Static(node) => static_node_to_value(ctx, *node),
            _ => parse_node(ctx, &tape, 0).map(|(value, _)| value),
        };
    }

    Undefined.into_js(ctx)
}

#[inline(always)]
fn static_node_to_value<'js>(ctx: &Ctx<'js>, node: StaticNode) -> Result<Value<'js>> {
    match node {
        StaticNode::I64(value) => value.into_js(ctx),
        StaticNode::U64(value) => value.into_js(ctx),
        StaticNode::F64(value) => value.into_js(ctx),
        StaticNode::Bool(value) => value.into_js(ctx),
        StaticNode::Null => Null.into_js(ctx),
    }
}

fn parse_node<'js>(ctx: &Ctx<'js>, tape: &[Node], index: usize) -> Result<(Value<'js>, usize)> {
    match &tape[index] {
        Node::String(value) => Ok((value.into_js(ctx)?, index + 1)),
        Node::Static(node) => Ok((static_node_to_value(ctx, *node)?, index + 1)),
        Node::Object { len, .. } => {
            let js_object = Object::new(ctx.clone())?;
            let mut current_index = index + 1;

            for _ in 0..*len {
                if let Node::String(key) = &tape[current_index] {
                    current_index += 1;
                    let (value, new_index) = parse_node(ctx, tape, current_index)?;
                    current_index = new_index;
                    js_object.set(*key, value)?;
                }
            }

            Ok((js_object.into_value(), current_index))
        }
        Node::Array { len, .. } => {
            let js_array = Array::new(ctx.clone())?;
            let mut current_index = index + 1;

            for i in 0..*len {
                let (value, new_index) = parse_node(ctx, tape, current_index)?;
                current_index = new_index;
                js_array.set(i, value)?;
            }

            Ok((js_array.into_value(), current_index))
        }
    }
}