ftl_jiter/
value.rs

1use std::borrow::Cow;
2use std::sync::Arc;
3
4#[cfg(feature = "num-bigint")]
5use num_bigint::BigInt;
6use smallvec::SmallVec;
7
8use crate::errors::{json_error, JsonError, JsonResult, DEFAULT_RECURSION_LIMIT};
9use crate::lazy_index_map::LazyIndexMap;
10use crate::number_decoder::{NumberAny, NumberInt, NumberRange};
11use crate::parse::{Parser, Peek};
12use crate::string_decoder::{StringDecoder, StringDecoderRange, StringOutput, Tape};
13
14/// Enum representing a JSON value.
15#[derive(Clone, Debug, PartialEq)]
16pub enum JsonValue<'s> {
17    Null,
18    Bool(bool),
19    Int(i64),
20    #[cfg(feature = "num-bigint")]
21    BigInt(BigInt),
22    Float(f64),
23    Str(Cow<'s, str>),
24    Array(JsonArray<'s>),
25    Object(JsonObject<'s>),
26}
27
28pub type JsonArray<'s> = Arc<SmallVec<[JsonValue<'s>; 8]>>;
29pub type JsonObject<'s> = Arc<LazyIndexMap<Cow<'s, str>, JsonValue<'s>>>;
30
31#[cfg(feature = "python")]
32impl pyo3::ToPyObject for JsonValue<'_> {
33    fn to_object(&self, py: pyo3::Python<'_>) -> pyo3::PyObject {
34        use pyo3::prelude::*;
35        match self {
36            Self::Null => py.None().to_object(py),
37            Self::Bool(b) => b.to_object(py),
38            Self::Int(i) => i.to_object(py),
39            #[cfg(feature = "num-bigint")]
40            Self::BigInt(b) => b.to_object(py),
41            Self::Float(f) => f.to_object(py),
42            Self::Str(s) => s.to_object(py),
43            Self::Array(v) => pyo3::types::PyList::new_bound(py, v.iter().map(|v| v.to_object(py))).to_object(py),
44            Self::Object(o) => {
45                let dict = pyo3::types::PyDict::new_bound(py);
46                for (k, v) in o.iter() {
47                    dict.set_item(k, v.to_object(py)).unwrap();
48                }
49                dict.to_object(py)
50            }
51        }
52    }
53}
54
55impl<'j> JsonValue<'j> {
56    /// Parse a JSON enum from a byte slice, returning a borrowed version of the enum - e.g. strings can be
57    /// references into the original byte slice.
58    pub fn parse(data: &'j [u8], allow_inf_nan: bool) -> Result<Self, JsonError> {
59        let mut parser = Parser::new(data);
60
61        let mut tape = Tape::default();
62        let peek = parser.peek()?;
63        let v = take_value_borrowed(peek, &mut parser, &mut tape, DEFAULT_RECURSION_LIMIT, allow_inf_nan)?;
64        parser.finish()?;
65        Ok(v)
66    }
67
68    /// Convert a borrowed JSON enum into an owned JSON enum.
69    pub fn into_static(self) -> JsonValue<'static> {
70        value_static(self)
71    }
72
73    /// Copy a borrowed JSON enum into an owned JSON enum.
74    pub fn to_static(&self) -> JsonValue<'static> {
75        value_static(self.clone())
76    }
77}
78
79fn value_static(v: JsonValue<'_>) -> JsonValue<'static> {
80    match v {
81        JsonValue::Null => JsonValue::Null,
82        JsonValue::Bool(b) => JsonValue::Bool(b),
83        JsonValue::Int(i) => JsonValue::Int(i),
84        #[cfg(feature = "num-bigint")]
85        JsonValue::BigInt(b) => JsonValue::BigInt(b),
86        JsonValue::Float(f) => JsonValue::Float(f),
87        JsonValue::Str(s) => JsonValue::Str(s.into_owned().into()),
88        JsonValue::Array(v) => JsonValue::Array(Arc::new(v.iter().map(JsonValue::to_static).collect::<SmallVec<_>>())),
89        JsonValue::Object(o) => JsonValue::Object(Arc::new(o.to_static())),
90    }
91}
92
93impl JsonValue<'static> {
94    /// Parse a JSON enum from a byte slice, returning an owned version of the enum.
95    pub fn parse_owned(data: &[u8], allow_inf_nan: bool) -> Result<Self, JsonError> {
96        let mut parser = Parser::new(data);
97
98        let mut tape = Tape::default();
99        let peek = parser.peek()?;
100        let v = take_value_owned(peek, &mut parser, &mut tape, DEFAULT_RECURSION_LIMIT, allow_inf_nan)?;
101        parser.finish()?;
102        Ok(v)
103    }
104}
105
106pub(crate) fn take_value_borrowed<'j>(
107    peek: Peek,
108    parser: &mut Parser<'j>,
109    tape: &mut Tape,
110    recursion_limit: u8,
111    allow_inf_nan: bool,
112) -> JsonResult<JsonValue<'j>> {
113    take_value(
114        peek,
115        parser,
116        tape,
117        recursion_limit,
118        allow_inf_nan,
119        &|s: StringOutput<'_, 'j>| s.into(),
120    )
121}
122
123pub(crate) fn take_value_owned<'j>(
124    peek: Peek,
125    parser: &mut Parser<'j>,
126    tape: &mut Tape,
127    recursion_limit: u8,
128    allow_inf_nan: bool,
129) -> JsonResult<JsonValue<'static>> {
130    take_value(
131        peek,
132        parser,
133        tape,
134        recursion_limit,
135        allow_inf_nan,
136        &|s: StringOutput<'_, 'j>| Into::<String>::into(s).into(),
137    )
138}
139
140fn take_value<'j, 's>(
141    peek: Peek,
142    parser: &mut Parser<'j>,
143    tape: &mut Tape,
144    recursion_limit: u8,
145    allow_inf_nan: bool,
146    create_cow: &impl Fn(StringOutput<'_, 'j>) -> Cow<'s, str>,
147) -> JsonResult<JsonValue<'s>> {
148    match peek {
149        Peek::True => {
150            parser.consume_true()?;
151            Ok(JsonValue::Bool(true))
152        }
153        Peek::False => {
154            parser.consume_false()?;
155            Ok(JsonValue::Bool(false))
156        }
157        Peek::Null => {
158            parser.consume_null()?;
159            Ok(JsonValue::Null)
160        }
161        Peek::String => {
162            let s: StringOutput<'_, 'j> = parser.consume_string::<StringDecoder>(tape, false)?;
163            Ok(JsonValue::Str(create_cow(s)))
164        }
165        Peek::Array => {
166            // we could do something clever about guessing the size of the array
167            let array = Arc::new(SmallVec::new());
168            if let Some(peek_first) = parser.array_first()? {
169                take_value_recursive(
170                    peek_first,
171                    RecursedValue::Array(array),
172                    parser,
173                    tape,
174                    recursion_limit,
175                    allow_inf_nan,
176                    create_cow,
177                )
178            } else {
179                Ok(JsonValue::Array(array))
180            }
181        }
182        Peek::Object => {
183            // same for objects
184            let object = Arc::new(LazyIndexMap::new());
185            if let Some(first_key) = parser.object_first::<StringDecoder>(tape)? {
186                let first_key = create_cow(first_key);
187                take_value_recursive(
188                    parser.peek()?,
189                    RecursedValue::Object {
190                        partial: object,
191                        next_key: first_key,
192                    },
193                    parser,
194                    tape,
195                    recursion_limit,
196                    allow_inf_nan,
197                    create_cow,
198                )
199            } else {
200                Ok(JsonValue::Object(object))
201            }
202        }
203        _ => {
204            let n = parser.consume_number::<NumberAny>(peek.into_inner(), allow_inf_nan);
205            match n {
206                Ok(NumberAny::Int(NumberInt::Int(int))) => Ok(JsonValue::Int(int)),
207                #[cfg(feature = "num-bigint")]
208                Ok(NumberAny::Int(NumberInt::BigInt(big_int))) => Ok(JsonValue::BigInt(big_int)),
209                Ok(NumberAny::Float(float)) => Ok(JsonValue::Float(float)),
210                Err(e) => {
211                    if !peek.is_num() {
212                        Err(json_error!(ExpectedSomeValue, parser.index))
213                    } else {
214                        Err(e)
215                    }
216                }
217            }
218        }
219    }
220}
221
222enum RecursedValue<'s> {
223    Array(JsonArray<'s>),
224    Object {
225        partial: JsonObject<'s>,
226        next_key: Cow<'s, str>,
227    },
228}
229
230#[inline(never)] // this is an iterative algo called only from take_value, no point in inlining
231#[allow(clippy::too_many_lines)] // FIXME?
232fn take_value_recursive<'j, 's>(
233    mut peek: Peek,
234    mut current_recursion: RecursedValue<'s>,
235    parser: &mut Parser<'j>,
236    tape: &mut Tape,
237    recursion_limit: u8,
238    allow_inf_nan: bool,
239    create_cow: &impl Fn(StringOutput<'_, 'j>) -> Cow<'s, str>,
240) -> JsonResult<JsonValue<'s>> {
241    let recursion_limit: usize = recursion_limit.into();
242
243    let mut recursion_stack: SmallVec<[RecursedValue; 8]> = SmallVec::new();
244
245    macro_rules! push_recursion {
246        ($next_peek:expr, $value:expr) => {
247            peek = $next_peek;
248            recursion_stack.push(std::mem::replace(&mut current_recursion, $value));
249            if recursion_stack.len() >= recursion_limit {
250                return Err(json_error!(RecursionLimitExceeded, parser.index));
251            }
252        };
253    }
254
255    'recursion: loop {
256        let mut value = match &mut current_recursion {
257            RecursedValue::Array(array) => {
258                let array = Arc::get_mut(array).expect("sole writer");
259                loop {
260                    let value = match peek {
261                        Peek::True => {
262                            parser.consume_true()?;
263                            JsonValue::Bool(true)
264                        }
265                        Peek::False => {
266                            parser.consume_false()?;
267                            JsonValue::Bool(false)
268                        }
269                        Peek::Null => {
270                            parser.consume_null()?;
271                            JsonValue::Null
272                        }
273                        Peek::String => {
274                            let s = parser.consume_string::<StringDecoder>(tape, false)?;
275                            JsonValue::Str(create_cow(s))
276                        }
277                        Peek::Array => {
278                            let array = Arc::new(SmallVec::new());
279                            if let Some(next_peek) = parser.array_first()? {
280                                push_recursion!(next_peek, RecursedValue::Array(array));
281                                // immediately jump to process the first value in the array
282                                continue 'recursion;
283                            }
284                            JsonValue::Array(array)
285                        }
286                        Peek::Object => {
287                            let object = Arc::new(LazyIndexMap::new());
288                            if let Some(next_key) = parser.object_first::<StringDecoder>(tape)? {
289                                push_recursion!(
290                                    parser.peek()?,
291                                    RecursedValue::Object {
292                                        partial: object,
293                                        next_key: create_cow(next_key)
294                                    }
295                                );
296                                continue 'recursion;
297                            }
298                            JsonValue::Object(object)
299                        }
300                        _ => {
301                            let n = parser
302                                .consume_number::<NumberAny>(peek.into_inner(), allow_inf_nan)
303                                .map_err(|e| {
304                                    if !peek.is_num() {
305                                        json_error!(ExpectedSomeValue, parser.index)
306                                    } else {
307                                        e
308                                    }
309                                })?;
310                            match n {
311                                NumberAny::Int(NumberInt::Int(int)) => JsonValue::Int(int),
312                                NumberAny::Int(NumberInt::BigInt(big_int)) => JsonValue::BigInt(big_int),
313                                NumberAny::Float(float) => JsonValue::Float(float),
314                            }
315                        }
316                    };
317
318                    // now try to advance position in the current array
319                    if let Some(next_peek) = parser.array_step()? {
320                        array.push(value);
321                        peek = next_peek;
322                        // array continuing
323                        continue;
324                    }
325
326                    let RecursedValue::Array(mut array) = current_recursion else {
327                        unreachable!("known to be in array recursion");
328                    };
329
330                    Arc::get_mut(&mut array).expect("sole writer to value").push(value);
331                    break JsonValue::Array(array);
332                }
333            }
334            RecursedValue::Object { partial, next_key } => {
335                let partial = Arc::get_mut(partial).expect("sole writer");
336                loop {
337                    let value = match peek {
338                        Peek::True => {
339                            parser.consume_true()?;
340                            JsonValue::Bool(true)
341                        }
342                        Peek::False => {
343                            parser.consume_false()?;
344                            JsonValue::Bool(false)
345                        }
346                        Peek::Null => {
347                            parser.consume_null()?;
348                            JsonValue::Null
349                        }
350                        Peek::String => {
351                            let s = parser.consume_string::<StringDecoder>(tape, false)?;
352                            JsonValue::Str(create_cow(s))
353                        }
354                        Peek::Array => {
355                            let array = Arc::new(SmallVec::new());
356                            if let Some(next_peek) = parser.array_first()? {
357                                push_recursion!(next_peek, RecursedValue::Array(array));
358                                // immediately jump to process the first value in the array
359                                continue 'recursion;
360                            }
361                            JsonValue::Array(array)
362                        }
363                        Peek::Object => {
364                            let object = Arc::new(LazyIndexMap::new());
365                            if let Some(yet_another_key) = parser.object_first::<StringDecoder>(tape)? {
366                                push_recursion!(
367                                    parser.peek()?,
368                                    RecursedValue::Object {
369                                        partial: object,
370                                        next_key: create_cow(yet_another_key)
371                                    }
372                                );
373                                continue 'recursion;
374                            }
375                            JsonValue::Object(object)
376                        }
377                        _ => {
378                            let n = parser
379                                .consume_number::<NumberAny>(peek.into_inner(), allow_inf_nan)
380                                .map_err(|e| {
381                                    if !peek.is_num() {
382                                        json_error!(ExpectedSomeValue, parser.index)
383                                    } else {
384                                        e
385                                    }
386                                })?;
387                            match n {
388                                NumberAny::Int(NumberInt::Int(int)) => JsonValue::Int(int),
389                                NumberAny::Int(NumberInt::BigInt(big_int)) => JsonValue::BigInt(big_int),
390                                NumberAny::Float(float) => JsonValue::Float(float),
391                            }
392                        }
393                    };
394
395                    // now try to advance position in the current object
396                    if let Some(yet_another_key) = parser.object_step::<StringDecoder>(tape)?.map(create_cow) {
397                        // object continuing
398                        partial.insert(std::mem::replace(next_key, yet_another_key), value);
399                        peek = parser.peek()?;
400                        continue;
401                    }
402
403                    let RecursedValue::Object { mut partial, next_key } = current_recursion else {
404                        unreachable!("known to be in object recursion");
405                    };
406
407                    Arc::get_mut(&mut partial).expect("sole writer").insert(next_key, value);
408                    break JsonValue::Object(partial);
409                }
410            }
411        };
412
413        // current array or object has finished;
414        // try to pop and continue with the parent
415        peek = loop {
416            if let Some(next_recursion) = recursion_stack.pop() {
417                current_recursion = next_recursion;
418            } else {
419                return Ok(value);
420            }
421
422            value = match current_recursion {
423                RecursedValue::Array(mut array) => {
424                    Arc::get_mut(&mut array).expect("sole writer").push(value);
425                    if let Some(next_peek) = parser.array_step()? {
426                        current_recursion = RecursedValue::Array(array);
427                        break next_peek;
428                    }
429                    JsonValue::Array(array)
430                }
431                RecursedValue::Object { mut partial, next_key } => {
432                    Arc::get_mut(&mut partial).expect("sole writer").insert(next_key, value);
433                    if let Some(next_key) = parser.object_step::<StringDecoder>(tape)?.map(create_cow) {
434                        current_recursion = RecursedValue::Object { partial, next_key };
435                        break parser.peek()?;
436                    }
437                    JsonValue::Object(partial)
438                }
439            }
440        };
441    }
442}
443
444/// like `take_value`, but nothing is returned, should be faster than `take_value`, useful when you don't care
445/// about the value, but just want to consume it
446pub(crate) fn take_value_skip(
447    peek: Peek,
448    parser: &mut Parser,
449    tape: &mut Tape,
450    recursion_limit: u8,
451    allow_inf_nan: bool,
452) -> JsonResult<()> {
453    match peek {
454        Peek::True => parser.consume_true(),
455        Peek::False => parser.consume_false(),
456        Peek::Null => parser.consume_null(),
457        Peek::String => parser.consume_string::<StringDecoderRange>(tape, false).map(drop),
458        Peek::Array => {
459            if let Some(next_peek) = parser.array_first()? {
460                take_value_skip_recursive(next_peek, ARRAY, parser, tape, recursion_limit, allow_inf_nan)
461            } else {
462                Ok(())
463            }
464        }
465        Peek::Object => {
466            if parser.object_first::<StringDecoderRange>(tape)?.is_some() {
467                take_value_skip_recursive(parser.peek()?, OBJECT, parser, tape, recursion_limit, allow_inf_nan)
468            } else {
469                Ok(())
470            }
471        }
472        _ => parser
473            .consume_number::<NumberRange>(peek.into_inner(), allow_inf_nan)
474            .map(drop)
475            .map_err(|e| {
476                if !peek.is_num() {
477                    json_error!(ExpectedSomeValue, parser.index)
478                } else {
479                    e
480                }
481            }),
482    }
483}
484
485const ARRAY: bool = false;
486const OBJECT: bool = true;
487
488#[inline(never)] // this is an iterative algo called only from take_value_skip, no point in inlining
489fn take_value_skip_recursive(
490    mut peek: Peek,
491    mut current_recursion: bool,
492    parser: &mut Parser,
493    tape: &mut Tape,
494    recursion_limit: u8,
495    allow_inf_nan: bool,
496) -> JsonResult<()> {
497    let mut recursion_stack = bitvec::bitarr![0; 256];
498    let recursion_limit: usize = recursion_limit.into();
499    let mut current_recursion_depth = 0;
500
501    macro_rules! push_recursion {
502        ($next_peek:expr, $value:expr) => {
503            peek = $next_peek;
504            recursion_stack.set(
505                current_recursion_depth,
506                std::mem::replace(&mut current_recursion, $value),
507            );
508            current_recursion_depth += 1;
509            if current_recursion_depth >= recursion_limit {
510                return Err(json_error!(RecursionLimitExceeded, parser.index));
511            }
512        };
513    }
514
515    loop {
516        match peek {
517            Peek::True => parser.consume_true()?,
518            Peek::False => parser.consume_false()?,
519            Peek::Null => parser.consume_null()?,
520            Peek::String => {
521                parser.consume_string::<StringDecoderRange>(tape, false)?;
522            }
523            Peek::Array => {
524                if let Some(next_peek) = parser.array_first()? {
525                    push_recursion!(next_peek, ARRAY);
526                    // immediately jump to process the first value in the array
527                    continue;
528                }
529            }
530            Peek::Object => {
531                if parser.object_first::<StringDecoderRange>(tape)?.is_some() {
532                    push_recursion!(parser.peek()?, OBJECT);
533                    // immediately jump to process the first value in the object
534                    continue;
535                }
536            }
537            _ => {
538                parser
539                    .consume_number::<NumberRange>(peek.into_inner(), allow_inf_nan)
540                    .map_err(|e| {
541                        if !peek.is_num() {
542                            json_error!(ExpectedSomeValue, parser.index)
543                        } else {
544                            e
545                        }
546                    })?;
547            }
548        };
549
550        // now try to advance position in the current array or object
551        peek = loop {
552            match current_recursion {
553                ARRAY => {
554                    if let Some(next_peek) = parser.array_step()? {
555                        break next_peek;
556                    }
557                }
558                OBJECT => {
559                    if parser.object_step::<StringDecoderRange>(tape)?.is_some() {
560                        break parser.peek()?;
561                    }
562                }
563            }
564
565            current_recursion_depth = match current_recursion_depth.checked_sub(1) {
566                Some(r) => r,
567                // no recursion left, we are done
568                None => return Ok(()),
569            };
570
571            current_recursion = recursion_stack[current_recursion_depth];
572        };
573    }
574}