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}