rqjs_ext/json/
parse.rs

1use crate::utils::result::ResultExt;
2use rquickjs::{Array, Ctx, IntoJs, Null, Object, Result, Undefined, Value};
3use simd_json::{Node, StaticNode};
4
5pub fn json_parse<'js, T: Into<Vec<u8>>>(ctx: &Ctx<'js>, json: T) -> Result<Value<'js>> {
6    let mut json: Vec<u8> = json.into();
7    let tape = simd_json::to_tape(&mut json).or_throw(ctx)?;
8    let tape = tape.0;
9
10    if let Some(first) = tape.first() {
11        return match first {
12            Node::String(value) => value.into_js(ctx),
13            Node::Static(node) => static_node_to_value(ctx, *node),
14            _ => parse_node(ctx, &tape, 0).map(|(value, _)| value),
15        };
16    }
17
18    Undefined.into_js(ctx)
19}
20
21#[inline(always)]
22fn static_node_to_value<'js>(ctx: &Ctx<'js>, node: StaticNode) -> Result<Value<'js>> {
23    match node {
24        StaticNode::I64(value) => value.into_js(ctx),
25        StaticNode::U64(value) => value.into_js(ctx),
26        StaticNode::F64(value) => value.into_js(ctx),
27        StaticNode::Bool(value) => value.into_js(ctx),
28        StaticNode::Null => Null.into_js(ctx),
29    }
30}
31
32fn parse_node<'js>(ctx: &Ctx<'js>, tape: &[Node], index: usize) -> Result<(Value<'js>, usize)> {
33    match &tape[index] {
34        Node::String(value) => Ok((value.into_js(ctx)?, index + 1)),
35        Node::Static(node) => Ok((static_node_to_value(ctx, *node)?, index + 1)),
36        Node::Object { len, .. } => {
37            let js_object = Object::new(ctx.clone())?;
38            let mut current_index = index + 1;
39
40            for _ in 0..*len {
41                if let Node::String(key) = &tape[current_index] {
42                    current_index += 1;
43                    let (value, new_index) = parse_node(ctx, tape, current_index)?;
44                    current_index = new_index;
45                    js_object.set(*key, value)?;
46                }
47            }
48
49            Ok((js_object.into_value(), current_index))
50        }
51        Node::Array { len, .. } => {
52            let js_array = Array::new(ctx.clone())?;
53            let mut current_index = index + 1;
54
55            for i in 0..*len {
56                let (value, new_index) = parse_node(ctx, tape, current_index)?;
57                current_index = new_index;
58                js_array.set(i, value)?;
59            }
60
61            Ok((js_array.into_value(), current_index))
62        }
63    }
64}