Skip to main content

azul_core/
json.rs

1//! JSON value types for C API (data definitions only, no serde_json dependency)
2//!
3//! The actual parsing/serialization lives in `azul_layout::json` which adds
4//! serde_json-based implementations on top of these types.
5
6use alloc::string::String;
7use alloc::vec::Vec;
8use core::fmt;
9use azul_css::{
10    AzString, OptionString, OptionF64, OptionBool,
11    impl_vec, impl_vec_clone, impl_vec_debug, impl_vec_partialeq, impl_vec_mut,
12    impl_result, impl_result_inner,
13    impl_option, impl_option_inner,
14};
15
16// ============================================================================
17// JSON Value Type
18// ============================================================================
19
20/// A generic JSON value that can hold any JSON type
21#[derive(Debug, Clone, PartialEq)]
22#[repr(C)]
23pub struct Json {
24    /// The type of this JSON value
25    pub value_type: JsonType,
26    /// Internal storage - interpretation depends on `value_type`
27    /// For objects/arrays, this contains serialized data
28    pub internal: JsonInternal,
29}
30
31/// Internal storage for JSON values.
32///
33/// This is a C-FFI-compatible tagged-union-via-struct: all fields always exist,
34/// but only the field(s) corresponding to `JsonType` in the parent `Json` are
35/// meaningful.  For compound types (`Array`, `Object`) the serialized JSON is
36/// stored in `string_value` and re-parsed on each access β€” this trades repeated
37/// parsing cost for a flat, FFI-safe layout with no interior pointers.
38#[derive(Debug, Clone, PartialEq)]
39#[repr(C)]
40pub struct JsonInternal {
41    /// For strings and serialized objects/arrays
42    pub string_value: AzString,
43    /// For numbers
44    pub number_value: f64,
45    /// For booleans
46    pub bool_value: bool,
47}
48
49impl Default for JsonInternal {
50    fn default() -> Self {
51        Self {
52            string_value: AzString::from(String::new()),
53            number_value: 0.0,
54            bool_value: false,
55        }
56    }
57}
58
59/// Type of a JSON value
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[repr(C)]
62pub enum JsonType {
63    /// JSON null
64    Null,
65    /// JSON boolean (true/false)
66    Bool,
67    /// JSON number (stored as f64)
68    Number,
69    /// JSON string
70    String,
71    /// JSON array
72    Array,
73    /// JSON object
74    Object,
75}
76
77/// Error when parsing JSON
78#[derive(Debug, Clone, PartialEq, Eq)]
79#[repr(C)]
80pub struct JsonParseError {
81    /// Error message
82    pub message: AzString,
83    /// Line number (if available)
84    pub line: u32,
85    /// Column number (if available)
86    pub column: u32,
87}
88
89impl fmt::Display for JsonParseError {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        if self.line > 0 {
92            write!(f, "{}:{}: {}", self.line, self.column, self.message.as_str())
93        } else {
94            write!(f, "{}", self.message.as_str())
95        }
96    }
97}
98
99#[cfg(feature = "std")]
100impl std::error::Error for JsonParseError {}
101
102/// A key-value pair in a JSON object
103#[derive(Debug, Clone, PartialEq)]
104#[repr(C)]
105pub struct JsonKeyValue {
106    /// The key
107    pub key: AzString,
108    /// The value
109    pub value: Json,
110}
111
112impl JsonKeyValue {
113    /// Create a new key-value pair
114    #[must_use] pub const fn create(key: AzString, value: Json) -> Self {
115        Self { key, value }
116    }
117}
118
119// ============================================================================
120// FFI-safe collection types
121// ============================================================================
122
123/// Option type for JsonKeyValue
124impl_option!(JsonKeyValue, OptionJsonKeyValue, copy = false, [Debug, Clone, PartialEq]);
125
126/// Vec of JsonKeyValue (FFI-safe)
127impl_vec!(JsonKeyValue, JsonKeyValueVec, JsonKeyValueVecDestructor, JsonKeyValueVecDestructorType, JsonKeyValueVecSlice, OptionJsonKeyValue);
128impl_vec_clone!(JsonKeyValue, JsonKeyValueVec, JsonKeyValueVecDestructor);
129impl_vec_debug!(JsonKeyValue, JsonKeyValueVec);
130
131impl JsonKeyValueVec {
132    /// Creates a new, heap-allocated `JsonKeyValueVec` by copying elements from a C array
133    #[inline]
134    #[allow(clippy::not_unsafe_ptr_arg_deref)] // SAFETY/FFI: `*const T` is the C-ABI signature; the fn null-checks then derefs under the documented caller contract (C guarantees a valid ptr/len). Marking it `unsafe fn` would force unsafe blocks into the generated dll bindings.
135    #[must_use] pub fn copy_from_array(ptr: *const JsonKeyValue, len: usize) -> Self {
136        if ptr.is_null() || len == 0 {
137            return Self::new();
138        }
139        let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
140        Self::from_vec(slice.to_vec())
141    }
142}
143
144// FFI-safe JsonVec using impl_vec! macro
145impl_vec!(Json, JsonVec, JsonVecDestructor, JsonVecDestructorType, JsonVecSlice, OptionJson);
146impl_vec_clone!(Json, JsonVec, JsonVecDestructor);
147impl_vec_debug!(Json, JsonVec);
148impl_vec_partialeq!(Json, JsonVec);
149impl_vec_mut!(Json, JsonVec);
150
151impl JsonVec {
152    /// Creates a new, heap-allocated `JsonVec` by copying elements from a C array
153    #[inline]
154    #[allow(clippy::not_unsafe_ptr_arg_deref)] // SAFETY/FFI: `*const T` is the C-ABI signature; the fn null-checks then derefs under the documented caller contract (C guarantees a valid ptr/len). Marking it `unsafe fn` would force unsafe blocks into the generated dll bindings.
155    #[must_use] pub fn copy_from_array(ptr: *const Json, len: usize) -> Self {
156        if ptr.is_null() || len == 0 {
157            return Self::new();
158        }
159        let slice = unsafe { core::slice::from_raw_parts(ptr, len) };
160        Self::from_vec(slice.to_vec())
161    }
162}
163
164// FFI-safe Result type for JSON parsing
165impl_result!(
166    Json,
167    JsonParseError,
168    ResultJsonJsonParseError,
169    copy = false,
170    [Debug, Clone, PartialEq]
171);
172
173// FFI-safe Option types for JSON
174impl_option!(Json, OptionJson, copy = false, [Clone, Debug, PartialEq]);
175impl_option!(JsonVec, OptionJsonVec, copy = false, [Clone, Debug]);
176impl_option!(JsonKeyValueVec, OptionJsonKeyValueVec, copy = false, [Clone, Debug]);
177
178// FFI-safe Option types for JSON value extraction
179// Note: OptionBool and OptionF64 are already exported from azul_css
180impl_option!(i64, OptionI64, [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]);
181
182// ============================================================================
183// Helpers
184// ============================================================================
185
186/// Try to losslessly convert an `f64` to `i64`.
187///
188/// Returns `Some` only when `n` is an integer that fits in `i64` without
189/// overflow.  The upper bound uses `< 2^63` (not `<= i64::MAX as f64`)
190/// because `i64::MAX` cannot be represented exactly in `f64` β€” the cast
191/// rounds up to `2^63`, which would cause overflow on `n as i64`.
192#[allow(clippy::cast_possible_truncation)] // bounded DPI/dimension/number conversion
193fn f64_as_i64(n: f64) -> Option<i64> {
194    if n.fract() == 0.0 && n >= -(2_f64.powi(63)) && n < 2_f64.powi(63) {
195        Some(n as i64)
196    } else {
197        None
198    }
199}
200
201// ============================================================================
202// Non-serde methods on Json (pure data, no parsing)
203// ============================================================================
204
205impl Json {
206    /// Create a null JSON value
207    #[must_use] pub fn null() -> Self {
208        Self {
209            value_type: JsonType::Null,
210            internal: JsonInternal::default(),
211        }
212    }
213
214    /// Create a boolean JSON value
215    #[must_use] pub fn bool(value: bool) -> Self {
216        Self {
217            value_type: JsonType::Bool,
218            internal: JsonInternal {
219                string_value: AzString::from(String::new()),
220                number_value: 0.0,
221                bool_value: value,
222            },
223        }
224    }
225
226    /// Create a number JSON value (floating-point)
227    #[must_use] pub fn number(value: f64) -> Self {
228        Self {
229            value_type: JsonType::Number,
230            internal: JsonInternal {
231                string_value: AzString::from(String::new()),
232                number_value: value,
233                bool_value: false,
234            },
235        }
236    }
237
238    /// Create an integer JSON value.
239    ///
240    /// **Note:** the value is stored as `f64` internally, so `i64` values with
241    /// magnitude greater than 2^53 will lose precision silently.
242    #[allow(clippy::cast_precision_loss)] // bounded DPI/dimension/number conversion
243    #[must_use] pub fn integer(value: i64) -> Self {
244        Self {
245            value_type: JsonType::Number,
246            internal: JsonInternal {
247                string_value: AzString::from(String::new()),
248                number_value: value as f64,
249                bool_value: false,
250            },
251        }
252    }
253
254    /// Create a string JSON value
255    pub fn string(value: impl Into<String>) -> Self {
256        Self {
257            value_type: JsonType::String,
258            internal: JsonInternal {
259                string_value: AzString::from(value.into()),
260                number_value: 0.0,
261                bool_value: false,
262            },
263        }
264    }
265
266    /// Check if this is null
267    #[must_use] pub fn is_null(&self) -> bool {
268        self.value_type == JsonType::Null
269    }
270
271    /// Check if this is a boolean
272    #[must_use] pub fn is_bool(&self) -> bool {
273        self.value_type == JsonType::Bool
274    }
275
276    /// Check if this is a number
277    #[must_use] pub fn is_number(&self) -> bool {
278        self.value_type == JsonType::Number
279    }
280
281    /// Check if this is a string
282    #[must_use] pub fn is_string(&self) -> bool {
283        self.value_type == JsonType::String
284    }
285
286    /// Check if this is an array
287    #[must_use] pub fn is_array(&self) -> bool {
288        self.value_type == JsonType::Array
289    }
290
291    /// Check if this is an object
292    #[must_use] pub fn is_object(&self) -> bool {
293        self.value_type == JsonType::Object
294    }
295
296    /// Get as boolean (returns None if not a bool)
297    #[must_use] pub fn as_bool(&self) -> OptionBool {
298        if self.value_type == JsonType::Bool {
299            OptionBool::Some(self.internal.bool_value)
300        } else {
301            OptionBool::None
302        }
303    }
304
305    /// Get as number (returns None if not a number)
306    #[must_use] pub fn as_number(&self) -> OptionF64 {
307        if self.value_type == JsonType::Number {
308            OptionF64::Some(self.internal.number_value)
309        } else {
310            OptionF64::None
311        }
312    }
313
314    /// Get as integer (returns None if not a number or not an integer)
315    #[must_use] pub fn as_i64(&self) -> OptionI64 {
316        if self.value_type == JsonType::Number {
317            f64_as_i64(self.internal.number_value).map_or(OptionI64::None, OptionI64::Some)
318        } else {
319            OptionI64::None
320        }
321    }
322
323    /// Get as string (returns None if not a string)
324    #[must_use] pub fn as_string(&self) -> OptionString {
325        if self.value_type == JsonType::String {
326            OptionString::Some(self.internal.string_value.clone())
327        } else {
328            OptionString::None
329        }
330    }
331
332    /// Get the raw internal string value (for arrays/objects this is the serialized JSON)
333    #[must_use] pub fn raw_string(&self) -> &str {
334        self.internal.string_value.as_str()
335    }
336}
337
338/// Note: the `Display` output is meant for human-readable / debug display.
339/// String values are quoted but **not** JSON-escaped (no backslash escaping
340/// of embedded quotes, newlines, etc.).  Use `to_json_string()` (requires
341/// the `serde-json` feature) when valid JSON output is needed.
342impl fmt::Display for Json {
343    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344        match self.value_type {
345            JsonType::Null => write!(f, "null"),
346            JsonType::Bool => write!(f, "{}", self.internal.bool_value),
347            JsonType::Number => {
348                let num = self.internal.number_value;
349                if let Some(i) = f64_as_i64(num) {
350                    write!(f, "{i}")
351                } else {
352                    write!(f, "{num}")
353                }
354            }
355            JsonType::String => write!(f, "\"{}\"", self.internal.string_value.as_str()),
356            JsonType::Array | JsonType::Object => {
357                write!(f, "{}", self.internal.string_value.as_str())
358            }
359        }
360    }
361}
362
363// ============================================================================
364// serde_json-dependent methods (gated behind "serde-json" feature)
365// ============================================================================
366
367#[cfg(feature = "serde-json")]
368impl Json {
369    /// Parse JSON from a string
370    pub fn parse(s: &str) -> Result<Self, JsonParseError> {
371        let value: serde_json::Value = serde_json::from_str(s).map_err(|e| {
372            JsonParseError {
373                message: AzString::from(alloc::format!("{}", e)),
374                line: e.line() as u32,
375                column: e.column() as u32,
376            }
377        })?;
378        Ok(Self::from_serde_value(value))
379    }
380
381    /// Parse JSON from bytes (UTF-8)
382    pub fn parse_bytes(bytes: &[u8]) -> Result<Self, JsonParseError> {
383        let value: serde_json::Value = serde_json::from_slice(bytes).map_err(|e| {
384            JsonParseError {
385                message: AzString::from(alloc::format!("{}", e)),
386                line: e.line() as u32,
387                column: e.column() as u32,
388            }
389        })?;
390        Ok(Self::from_serde_value(value))
391    }
392
393    /// Convert from serde_json::Value
394    pub fn from_serde_value(value: serde_json::Value) -> Self {
395        match value {
396            serde_json::Value::Null => Self::null(),
397            serde_json::Value::Bool(b) => Self::bool(b),
398            serde_json::Value::Number(n) => Self::number(n.as_f64().unwrap_or(0.0)),
399            serde_json::Value::String(s) => Self::string(s),
400            serde_json::Value::Array(arr) => {
401                let json_str = serde_json::to_string(&serde_json::Value::Array(arr)).unwrap_or_default();
402                Self {
403                    value_type: JsonType::Array,
404                    internal: JsonInternal {
405                        string_value: AzString::from(json_str),
406                        number_value: 0.0,
407                        bool_value: false,
408                    },
409                }
410            }
411            serde_json::Value::Object(obj) => {
412                let json_str = serde_json::to_string(&serde_json::Value::Object(obj)).unwrap_or_default();
413                Self {
414                    value_type: JsonType::Object,
415                    internal: JsonInternal {
416                        string_value: AzString::from(json_str),
417                        number_value: 0.0,
418                        bool_value: false,
419                    },
420                }
421            }
422        }
423    }
424
425    /// Convert this Json to a serde_json::Value
426    pub fn to_serde_value(&self) -> serde_json::Value {
427        match self.value_type {
428            JsonType::Null => serde_json::Value::Null,
429            JsonType::Bool => serde_json::Value::Bool(self.internal.bool_value),
430            JsonType::Number => {
431                let num = self.internal.number_value;
432                if let Some(i) = f64_as_i64(num) {
433                    serde_json::Value::Number(serde_json::Number::from(i))
434                } else {
435                    serde_json::Number::from_f64(num)
436                        .map(serde_json::Value::Number)
437                        .unwrap_or(serde_json::Value::Null)
438                }
439            }
440            JsonType::String => serde_json::Value::String(self.internal.string_value.as_str().to_string()),
441            JsonType::Array | JsonType::Object => {
442                serde_json::from_str(self.internal.string_value.as_str())
443                    .unwrap_or(serde_json::Value::Null)
444            }
445        }
446    }
447
448    /// Create a JSON array from a vector of JSON values
449    pub fn array(values: JsonVec) -> Self {
450        let serde_array: Vec<serde_json::Value> = values
451            .as_slice()
452            .iter()
453            .map(|j| j.to_serde_value())
454            .collect();
455        let json_str = serde_json::to_string(&serde_json::Value::Array(serde_array))
456            .unwrap_or_else(|_| "[]".to_string());
457        Self {
458            value_type: JsonType::Array,
459            internal: JsonInternal {
460                string_value: AzString::from(json_str),
461                number_value: 0.0,
462                bool_value: false,
463            },
464        }
465    }
466
467    /// Create a JSON object from key-value pairs
468    pub fn object(entries: JsonKeyValueVec) -> Self {
469        let mut map = serde_json::Map::new();
470        for kv in entries.as_slice() {
471            map.insert(kv.key.as_str().to_string(), kv.value.to_serde_value());
472        }
473        let json_str = serde_json::to_string(&serde_json::Value::Object(map))
474            .unwrap_or_else(|_| "{}".to_string());
475        Self {
476            value_type: JsonType::Object,
477            internal: JsonInternal {
478                string_value: AzString::from(json_str),
479                number_value: 0.0,
480                bool_value: false,
481            },
482        }
483    }
484
485    /// Get the number of elements (for arrays) or keys (for objects)
486    pub fn len(&self) -> usize {
487        match self.value_type {
488            JsonType::Array => {
489                if let Ok(serde_json::Value::Array(arr)) = serde_json::from_str(self.internal.string_value.as_str()) {
490                    arr.len()
491                } else {
492                    0
493                }
494            }
495            JsonType::Object => {
496                if let Ok(serde_json::Value::Object(obj)) = serde_json::from_str(self.internal.string_value.as_str()) {
497                    obj.len()
498                } else {
499                    0
500                }
501            }
502            _ => 0,
503        }
504    }
505
506    /// Check if empty (for arrays/objects)
507    pub fn is_empty(&self) -> bool {
508        self.len() == 0
509    }
510
511    /// Get array element by index
512    pub fn get_index(&self, index: usize) -> Option<Json> {
513        if self.value_type != JsonType::Array { return None; }
514        let value: serde_json::Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
515        if let serde_json::Value::Array(arr) = value {
516            arr.get(index).map(|v| Self::from_serde_value(v.clone()))
517        } else {
518            None
519        }
520    }
521
522    /// Get object value by key
523    pub fn get_key(&self, key: &str) -> Option<Json> {
524        if self.value_type != JsonType::Object { return None; }
525        let value: serde_json::Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
526        if let serde_json::Value::Object(obj) = value {
527            obj.get(key).map(|v| Self::from_serde_value(v.clone()))
528        } else {
529            None
530        }
531    }
532
533    /// Get all keys of an object
534    pub fn keys(&self) -> Vec<AzString> {
535        if self.value_type != JsonType::Object { return Vec::new(); }
536        let value: serde_json::Value = match serde_json::from_str(self.internal.string_value.as_str()) {
537            Ok(v) => v,
538            Err(_) => return Vec::new(),
539        };
540        if let serde_json::Value::Object(obj) = value {
541            obj.keys().map(|k| AzString::from(k.clone())).collect()
542        } else {
543            Vec::new()
544        }
545    }
546
547    /// Convert array to Vec<Json>
548    pub fn to_array(&self) -> Option<JsonVec> {
549        if self.value_type != JsonType::Array { return None; }
550        let value: serde_json::Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
551        if let serde_json::Value::Array(arr) = value {
552            Some(arr.into_iter().map(Self::from_serde_value).collect())
553        } else {
554            None
555        }
556    }
557
558    /// Convert object to Vec<JsonKeyValue>
559    pub fn to_object(&self) -> Option<JsonKeyValueVec> {
560        if self.value_type != JsonType::Object { return None; }
561        let value: serde_json::Value = serde_json::from_str(self.internal.string_value.as_str()).ok()?;
562        if let serde_json::Value::Object(obj) = value {
563            Some(obj.into_iter().map(|(k, v)| JsonKeyValue {
564                key: AzString::from(k),
565                value: Self::from_serde_value(v),
566            }).collect())
567        } else {
568            None
569        }
570    }
571
572    /// Serialize to JSON string (returns AzString)
573    pub fn to_json_string(&self) -> AzString {
574        match self.value_type {
575            JsonType::Null => AzString::from(alloc::string::String::from("null")),
576            JsonType::Bool => AzString::from(if self.internal.bool_value { alloc::string::String::from("true") } else { alloc::string::String::from("false") }),
577            JsonType::Number => {
578                let num = self.internal.number_value;
579                if let Some(i) = f64_as_i64(num) {
580                    AzString::from(alloc::format!("{}", i))
581                } else {
582                    AzString::from(alloc::format!("{}", num))
583                }
584            }
585            JsonType::String => {
586                let escaped = serde_json::to_string(self.internal.string_value.as_str()).unwrap_or_default();
587                AzString::from(escaped)
588            }
589            JsonType::Array | JsonType::Object => {
590                self.internal.string_value.clone()
591            }
592        }
593    }
594
595    /// Serialize to pretty-printed JSON string
596    pub fn to_string_pretty(&self) -> AzString {
597        match self.value_type {
598            JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
599                self.to_json_string()
600            }
601            JsonType::Array | JsonType::Object => {
602                if let Ok(value) = serde_json::from_str::<serde_json::Value>(self.internal.string_value.as_str()) {
603                    AzString::from(serde_json::to_string_pretty(&value).unwrap_or_default())
604                } else {
605                    self.internal.string_value.clone()
606                }
607            }
608        }
609    }
610
611    /// Access a nested value using a JSON Pointer (RFC 6901).
612    pub fn jq(&self, path: &str) -> Json {
613        match self.value_type {
614            JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
615                if path.is_empty() { self.clone() } else { Json::null() }
616            }
617            JsonType::Array | JsonType::Object => {
618                let value: serde_json::Value = match serde_json::from_str(self.internal.string_value.as_str()) {
619                    Ok(v) => v,
620                    Err(_) => return Json::null(),
621                };
622                match value.pointer(path) {
623                    Some(v) => Self::from_serde_value(v.clone()),
624                    None => Json::null(),
625                }
626            }
627        }
628    }
629
630    /// Access nested values using a JSON Pointer with wildcard support.
631    pub fn jq_all(&self, path: &str) -> JsonVec {
632        let result = match self.value_type {
633            JsonType::Null | JsonType::Bool | JsonType::Number | JsonType::String => {
634                if path.is_empty() { vec![self.clone()] } else { vec![] }
635            }
636            JsonType::Array | JsonType::Object => {
637                let value: serde_json::Value = match serde_json::from_str(self.internal.string_value.as_str()) {
638                    Ok(v) => v,
639                    Err(_) => return JsonVec::from_vec(vec![]),
640                };
641                Self::jq_all_recursive(&value, path)
642            }
643        };
644        JsonVec::from_vec(result)
645    }
646
647    /// Maximum JSON-Pointer component depth for [`jq_all`](Self::jq_all).
648    ///
649    /// AUDIT 2026-07-08: `jq_all_recursive` recursed once per pointer component,
650    /// so an attacker-supplied pointer with tens of thousands of `/` segments
651    /// (e.g. `"/a".repeat(100_000)`) overflowed the stack. The single-child
652    /// descent is now iterative (unbounded, allocation-free); only the wildcard
653    /// (`*`) fan-out still recurses, and that recursion is capped here. 512 is far
654    /// deeper than any real document nesting while staying well inside the stack.
655    const JQ_MAX_WILDCARD_DEPTH: usize = 512;
656
657    /// Recursive helper for jq_all that handles wildcards.
658    ///
659    /// Non-wildcard components are walked in a loop so a long linear pointer can
660    /// never overflow the stack; only `*` fan-out recurses, bounded by
661    /// [`JQ_MAX_WILDCARD_DEPTH`](Self::JQ_MAX_WILDCARD_DEPTH).
662    fn jq_all_recursive(value: &serde_json::Value, path: &str) -> Vec<Json> {
663        Self::jq_all_recursive_depth(value, path, 0)
664    }
665
666    fn jq_all_recursive_depth(
667        value: &serde_json::Value,
668        path: &str,
669        depth: usize,
670    ) -> Vec<Json> {
671        // Guard the wildcard recursion; exceeding the cap yields no match rather
672        // than crashing.
673        if depth > Self::JQ_MAX_WILDCARD_DEPTH {
674            return vec![];
675        }
676
677        // Walk non-wildcard components iteratively.
678        let mut value = value;
679        let mut path = path;
680        loop {
681            if path.is_empty() {
682                return vec![Self::from_serde_value(value.clone())];
683            }
684            if !path.starts_with('/') {
685                return vec![];
686            }
687            let rest = &path[1..];
688            let (component, remaining) = match rest.find('/') {
689                Some(idx) => (&rest[..idx], &rest[idx..]),
690                None => (rest, ""),
691            };
692
693            if component == "*" {
694                let mut results = Vec::new();
695                match value {
696                    serde_json::Value::Array(arr) => {
697                        for item in arr {
698                            results.extend(Self::jq_all_recursive_depth(
699                                item,
700                                remaining,
701                                depth + 1,
702                            ));
703                        }
704                    }
705                    serde_json::Value::Object(obj) => {
706                        for (_key, val) in obj {
707                            results.extend(Self::jq_all_recursive_depth(
708                                val,
709                                remaining,
710                                depth + 1,
711                            ));
712                        }
713                    }
714                    _ => {}
715                }
716                return results;
717            }
718
719            // Single-child descent: advance the cursor instead of recursing.
720            let next = match value {
721                serde_json::Value::Array(arr) => {
722                    component.parse::<usize>().ok().and_then(|idx| arr.get(idx))
723                }
724                serde_json::Value::Object(obj) => obj.get(component),
725                _ => None,
726            };
727            match next {
728                Some(v) => {
729                    value = v;
730                    path = remaining;
731                }
732                None => return vec![],
733            }
734        }
735    }
736}
737
738#[cfg(test)]
739mod jq_recursion_tests {
740    use super::*;
741
742    /// AUDIT 2026-07-08: a pointer with a very large number of components used to
743    /// overflow the stack via per-component recursion. Linear (non-wildcard)
744    /// descent is now iterative, so an over-long pointer against a shallow
745    /// document returns empty promptly with zero recursion instead of a deep call
746    /// chain. `serde_json`'s own 128-level parse cap keeps documents shallow, but
747    /// this guarantees the jq walk itself never blows the stack on a huge pointer.
748    #[test]
749    #[cfg(feature = "serde-json")]
750    fn huge_pointer_on_shallow_doc_returns_empty() {
751        let json = Json::parse("{\"a\":{\"b\":1}}").expect("parse");
752        let pointer = "/a".repeat(200_000);
753        assert_eq!(json.jq_all(&pointer).as_ref().len(), 0);
754    }
755
756    /// A moderately deep linear pointer (within serde's parse limit) resolves to
757    /// its single leaf via the iterative descent.
758    #[test]
759    #[cfg(feature = "serde-json")]
760    fn deep_linear_pointer_resolves_leaf() {
761        const DEPTH: usize = 100; // below serde_json's 128-level parse cap
762
763        let mut doc = String::new();
764        for _ in 0..DEPTH {
765            doc.push_str("{\"a\":");
766        }
767        doc.push_str("42");
768        for _ in 0..DEPTH {
769            doc.push('}');
770        }
771
772        let json = Json::parse(&doc).expect("deep doc should parse");
773        let pointer = "/a".repeat(DEPTH);
774        let out = json.jq_all(&pointer);
775        assert_eq!(out.as_ref().len(), 1, "the single leaf should be found");
776    }
777
778    /// Ordinary wildcard + index access still works after the iterative rewrite.
779    #[test]
780    #[cfg(feature = "serde-json")]
781    fn wildcard_and_index_still_work() {
782        let json = Json::parse("{\"items\":[{\"v\":1},{\"v\":2},{\"v\":3}]}").expect("parse");
783        let all = json.jq_all("/items/*/v");
784        assert_eq!(all.as_ref().len(), 3);
785        let one = json.jq_all("/items/1/v");
786        assert_eq!(one.as_ref().len(), 1);
787    }
788}
789
790#[cfg(test)]
791#[allow(clippy::float_cmp, clippy::unreadable_literal)]
792mod autotest_generated {
793    use super::*;
794
795    // ------------------------------------------------------------------
796    // helpers
797    // ------------------------------------------------------------------
798
799    fn az(s: &str) -> AzString {
800        AzString::from(String::from(s))
801    }
802
803    /// Build a `Json` by hand, bypassing the constructors. Used to feed the
804    /// accessors a *corrupt* value (e.g. `value_type: Array` whose internal
805    /// string is not parseable JSON) β€” reachable over FFI because every field
806    /// of `Json` / `JsonInternal` is `pub`.
807    fn raw(value_type: JsonType, string_value: &str) -> Json {
808        Json {
809            value_type,
810            internal: JsonInternal {
811                string_value: az(string_value),
812                number_value: 0.0,
813                bool_value: false,
814            },
815        }
816    }
817
818    fn two_pow_63() -> f64 {
819        2_f64.powi(63)
820    }
821
822    // ==================================================================
823    // f64_as_i64  (numeric: zero / min_max / negative / overflow / nan_inf)
824    // ==================================================================
825
826    #[test]
827    fn f64_as_i64_zero_and_negative_zero() {
828        assert_eq!(f64_as_i64(0.0), Some(0));
829        // -0.0 is an integer and in range: the sign is silently dropped.
830        assert_eq!(f64_as_i64(-0.0), Some(0));
831    }
832
833    #[test]
834    fn f64_as_i64_min_max_boundaries() {
835        // -2^63 is exactly representable and is exactly i64::MIN.
836        assert_eq!(f64_as_i64(-two_pow_63()), Some(i64::MIN));
837        // +2^63 is NOT a valid i64 β€” must be rejected rather than wrapping.
838        assert_eq!(f64_as_i64(two_pow_63()), None);
839        // i64::MAX rounds *up* to 2^63 when cast to f64, so it is rejected too.
840        // This is the documented reason the bound is `< 2^63` and not `<= MAX`.
841        #[allow(clippy::cast_precision_loss)]
842        let max_as_f64 = i64::MAX as f64;
843        assert_eq!(max_as_f64, two_pow_63());
844        assert_eq!(f64_as_i64(max_as_f64), None);
845        // The largest f64 that is a valid i64: 2^63 - 1024.
846        let just_below = two_pow_63() - 1024.0;
847        assert_eq!(f64_as_i64(just_below), Some(9_223_372_036_854_774_784));
848    }
849
850    #[test]
851    fn f64_as_i64_negatives_are_deterministic() {
852        assert_eq!(f64_as_i64(-1.0), Some(-1));
853        assert_eq!(f64_as_i64(-42.0), Some(-42));
854        assert_eq!(f64_as_i64(-0.5), None);
855        assert_eq!(f64_as_i64(-1.0 - f64::EPSILON), None);
856        // One ULP below -2^63 is out of range.
857        assert_eq!(f64_as_i64(-two_pow_63() * (1.0 + f64::EPSILON)), None);
858    }
859
860    #[test]
861    fn f64_as_i64_overflow_inputs_return_none_not_a_wrapped_cast() {
862        for n in [
863            1e19_f64,
864            1e300_f64,
865            -1e300_f64,
866            f64::MAX,
867            f64::MIN,
868            two_pow_63() * 2.0,
869        ] {
870            assert_eq!(f64_as_i64(n), None, "{n} must not be cast to i64");
871        }
872    }
873
874    #[test]
875    fn f64_as_i64_nan_and_infinity_do_not_panic() {
876        // NaN.fract() is NaN, and NaN == 0.0 is false, so all three fall through
877        // to `None` without ever reaching the (UB-adjacent) `as i64` cast.
878        assert_eq!(f64_as_i64(f64::NAN), None);
879        assert_eq!(f64_as_i64(f64::INFINITY), None);
880        assert_eq!(f64_as_i64(f64::NEG_INFINITY), None);
881    }
882
883    #[test]
884    fn f64_as_i64_fractional_and_subnormal_return_none() {
885        assert_eq!(f64_as_i64(0.5), None);
886        assert_eq!(f64_as_i64(f64::EPSILON), None);
887        assert_eq!(f64_as_i64(f64::MIN_POSITIVE), None);
888        // Smallest subnormal.
889        assert_eq!(f64_as_i64(f64::from_bits(1)), None);
890    }
891
892    // ==================================================================
893    // Json::number / Json::integer  (numeric)
894    // ==================================================================
895
896    #[test]
897    fn number_stores_nan_and_infinity_without_panicking() {
898        for n in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
899            let j = Json::number(n);
900            assert!(j.is_number());
901            assert_eq!(j.as_i64(), OptionI64::None);
902            match j.as_number() {
903                OptionF64::Some(v) => assert_eq!(v.is_nan(), n.is_nan()),
904                OptionF64::None => panic!("as_number() must be Some for a Number"),
905            }
906            // Display must not panic on non-finite floats.
907            let s = alloc::format!("{j}");
908            assert!(!s.is_empty());
909        }
910    }
911
912    #[test]
913    fn number_min_max_and_zero() {
914        assert_eq!(Json::number(0.0).as_i64(), OptionI64::Some(0));
915        assert_eq!(Json::number(-0.0).as_i64(), OptionI64::Some(0));
916        assert_eq!(Json::number(f64::MAX).as_number(), OptionF64::Some(f64::MAX));
917        assert_eq!(Json::number(f64::MIN).as_number(), OptionF64::Some(f64::MIN));
918        // Huge-but-finite values are numbers, but not integers.
919        assert_eq!(Json::number(f64::MAX).as_i64(), OptionI64::None);
920    }
921
922    #[test]
923    fn integer_min_round_trips_but_max_does_not() {
924        // i64::MIN == -2^63 is exactly representable in f64.
925        assert_eq!(Json::integer(i64::MIN).as_i64(), OptionI64::Some(i64::MIN));
926        // i64::MAX is NOT: `value as f64` rounds it up to 2^63, which is out of
927        // i64 range, so the value cannot be read back. Documented on the fn as
928        // "silent precision loss" for |value| > 2^53.
929        assert_eq!(Json::integer(i64::MAX).as_i64(), OptionI64::None);
930        assert_eq!(
931            Json::integer(i64::MAX).as_number(),
932            OptionF64::Some(two_pow_63())
933        );
934    }
935
936    #[test]
937    fn integer_silently_loses_precision_above_2_pow_53() {
938        let boundary = 1_i64 << 53; // 9_007_199_254_740_992
939        assert_eq!(Json::integer(boundary).as_i64(), OptionI64::Some(boundary));
940        // 2^53 + 1 is not representable: it rounds *down* to 2^53.
941        assert_eq!(
942            Json::integer(boundary + 1).as_i64(),
943            OptionI64::Some(boundary)
944        );
945        assert_eq!(Json::integer(0).as_i64(), OptionI64::Some(0));
946        assert_eq!(Json::integer(-1).as_i64(), OptionI64::Some(-1));
947    }
948
949    // ==================================================================
950    // constructors + predicates  (predicate: basic_true_false / edge_inputs)
951    // ==================================================================
952
953    #[test]
954    fn predicates_are_mutually_exclusive_for_every_type() {
955        let cases = [
956            (Json::null(), JsonType::Null),
957            (Json::bool(false), JsonType::Bool),
958            (Json::number(f64::NAN), JsonType::Number),
959            (Json::integer(0), JsonType::Number),
960            (Json::string(""), JsonType::String),
961            (raw(JsonType::Array, "[]"), JsonType::Array),
962            (raw(JsonType::Object, "{}"), JsonType::Object),
963        ];
964        for (j, ty) in &cases {
965            let flags = [
966                j.is_null(),
967                j.is_bool(),
968                j.is_number(),
969                j.is_string(),
970                j.is_array(),
971                j.is_object(),
972            ];
973            assert_eq!(
974                flags.iter().filter(|b| **b).count(),
975                1,
976                "exactly one predicate must hold for {ty:?}"
977            );
978            assert_eq!(j.value_type, *ty);
979        }
980    }
981
982    #[test]
983    fn predicates_on_a_default_internal_do_not_panic() {
984        // A hand-rolled Json with a default (empty) payload β€” the FFI worst case.
985        for ty in [
986            JsonType::Null,
987            JsonType::Bool,
988            JsonType::Number,
989            JsonType::String,
990            JsonType::Array,
991            JsonType::Object,
992        ] {
993            let j = Json {
994                value_type: ty,
995                internal: JsonInternal::default(),
996            };
997            assert_eq!(j.is_null(), ty == JsonType::Null);
998            assert_eq!(j.is_object(), ty == JsonType::Object);
999            assert_eq!(j.raw_string(), "");
1000        }
1001    }
1002
1003    #[test]
1004    fn bool_constructor_keeps_both_values() {
1005        assert_eq!(Json::bool(true).as_bool(), OptionBool::Some(true));
1006        assert_eq!(Json::bool(false).as_bool(), OptionBool::Some(false));
1007        // The unused payload fields are zeroed, which the derived PartialEq relies on.
1008        assert_eq!(Json::bool(true).raw_string(), "");
1009        assert_eq!(Json::bool(true).as_number(), OptionF64::None);
1010    }
1011
1012    #[test]
1013    fn string_constructor_handles_empty_unicode_and_huge_inputs() {
1014        assert_eq!(Json::string("").as_string(), OptionString::Some(az("")));
1015
1016        let unicode = "πŸ˜€ nÑïve \u{0301}\u{202e}\0 δΈ­ζ–‡";
1017        assert_eq!(
1018            Json::string(unicode).as_string(),
1019            OptionString::Some(az(unicode))
1020        );
1021        assert_eq!(Json::string(unicode).raw_string(), unicode);
1022
1023        let huge = "a".repeat(1_000_000);
1024        let j = Json::string(huge.clone());
1025        assert_eq!(j.raw_string().len(), 1_000_000);
1026        assert_eq!(j.as_string(), OptionString::Some(AzString::from(huge)));
1027    }
1028
1029    // ==================================================================
1030    // getters  (getter: basic_access / edge_access)
1031    // ==================================================================
1032
1033    #[test]
1034    fn getters_return_none_on_type_mismatch() {
1035        let null = Json::null();
1036        assert_eq!(null.as_bool(), OptionBool::None);
1037        assert_eq!(null.as_number(), OptionF64::None);
1038        assert_eq!(null.as_i64(), OptionI64::None);
1039        assert_eq!(null.as_string(), OptionString::None);
1040
1041        // A Bool whose *number* payload happens to be set must still not be
1042        // readable as a number (the tag, not the payload, decides).
1043        let mut liar = Json::bool(true);
1044        liar.internal.number_value = 7.0;
1045        liar.internal.string_value = az("7");
1046        assert_eq!(liar.as_number(), OptionF64::None);
1047        assert_eq!(liar.as_i64(), OptionI64::None);
1048        assert_eq!(liar.as_string(), OptionString::None);
1049        assert_eq!(liar.as_bool(), OptionBool::Some(true));
1050        // ...but raw_string() is the *unchecked* accessor and does hand it back.
1051        assert_eq!(liar.raw_string(), "7");
1052    }
1053
1054    #[test]
1055    fn raw_string_is_empty_for_scalars_and_serialized_for_containers() {
1056        assert_eq!(Json::null().raw_string(), "");
1057        assert_eq!(Json::bool(true).raw_string(), "");
1058        assert_eq!(Json::number(1.5).raw_string(), "");
1059        assert_eq!(Json::string("hi").raw_string(), "hi");
1060        assert_eq!(raw(JsonType::Array, "[1,2]").raw_string(), "[1,2]");
1061        // Corrupt payloads are handed back verbatim, never panic.
1062        assert_eq!(raw(JsonType::Object, "{not json").raw_string(), "{not json");
1063    }
1064
1065    // ==================================================================
1066    // Display for Json  (round_trip / serializer)
1067    // ==================================================================
1068
1069    #[test]
1070    fn display_scalar_values() {
1071        assert_eq!(alloc::format!("{}", Json::null()), "null");
1072        assert_eq!(alloc::format!("{}", Json::bool(true)), "true");
1073        assert_eq!(alloc::format!("{}", Json::bool(false)), "false");
1074        // Integral floats print without a fractional part (via f64_as_i64).
1075        assert_eq!(alloc::format!("{}", Json::number(3.0)), "3");
1076        assert_eq!(alloc::format!("{}", Json::integer(-42)), "-42");
1077        assert_eq!(alloc::format!("{}", Json::number(1.5)), "1.5");
1078        assert_eq!(alloc::format!("{}", Json::string("x")), "\"x\"");
1079    }
1080
1081    #[test]
1082    fn display_of_non_finite_numbers_is_not_json() {
1083        // Characterization: Display is documented as human-readable, NOT JSON.
1084        assert_eq!(alloc::format!("{}", Json::number(f64::NAN)), "NaN");
1085        assert_eq!(alloc::format!("{}", Json::number(f64::INFINITY)), "inf");
1086        assert_eq!(alloc::format!("{}", Json::number(f64::NEG_INFINITY)), "-inf");
1087        // -0.0 loses its sign because f64_as_i64(-0.0) == Some(0).
1088        assert_eq!(alloc::format!("{}", Json::number(-0.0)), "0");
1089    }
1090
1091    #[test]
1092    fn display_does_not_escape_strings() {
1093        // Documented caveat on the Display impl: embedded quotes/newlines are
1094        // NOT escaped, so the output is deliberately not valid JSON.
1095        let j = Json::string("a\"b\nc");
1096        assert_eq!(alloc::format!("{j}"), "\"a\"b\nc\"");
1097    }
1098
1099    #[test]
1100    fn display_of_container_emits_the_raw_payload_even_when_corrupt() {
1101        assert_eq!(
1102            alloc::format!("{}", raw(JsonType::Array, "[1, 2]")),
1103            "[1, 2]"
1104        );
1105        assert_eq!(
1106            alloc::format!("{}", raw(JsonType::Object, "<<garbage>>")),
1107            "<<garbage>>"
1108        );
1109        assert_eq!(alloc::format!("{}", raw(JsonType::Array, "")), "");
1110    }
1111
1112    // ==================================================================
1113    // JsonParseError::fmt  (serializer)
1114    // ==================================================================
1115
1116    #[test]
1117    fn parse_error_display_with_and_without_position() {
1118        let with_pos = JsonParseError {
1119            message: az("expected value"),
1120            line: 3,
1121            column: 7,
1122        };
1123        assert_eq!(alloc::format!("{with_pos}"), "3:7: expected value");
1124
1125        let no_pos = JsonParseError {
1126            message: az("expected value"),
1127            line: 0,
1128            column: 99,
1129        };
1130        assert_eq!(alloc::format!("{no_pos}"), "expected value");
1131    }
1132
1133    #[test]
1134    fn parse_error_display_edge_values_do_not_panic() {
1135        let empty = JsonParseError {
1136            message: az(""),
1137            line: 0,
1138            column: 0,
1139        };
1140        assert_eq!(alloc::format!("{empty}"), "");
1141
1142        let maxed = JsonParseError {
1143            message: az("πŸ˜€"),
1144            line: u32::MAX,
1145            column: u32::MAX,
1146        };
1147        assert_eq!(
1148            alloc::format!("{maxed}"),
1149            alloc::format!("{}:{}: πŸ˜€", u32::MAX, u32::MAX)
1150        );
1151    }
1152
1153    // ==================================================================
1154    // JsonKeyValue::create  (other: no_panic_smoke)
1155    // ==================================================================
1156
1157    #[test]
1158    fn key_value_create_preserves_key_and_value() {
1159        let kv = JsonKeyValue::create(az(""), Json::null());
1160        assert_eq!(kv.key.as_str(), "");
1161        assert!(kv.value.is_null());
1162
1163        let big_key = "k".repeat(100_000);
1164        let kv = JsonKeyValue::create(
1165            AzString::from(big_key.clone()),
1166            Json::number(f64::NEG_INFINITY),
1167        );
1168        assert_eq!(kv.key.as_str().len(), big_key.len());
1169        assert!(kv.value.is_number());
1170
1171        let kv = JsonKeyValue::create(az("πŸ˜€/\u{0}"), Json::string("v"));
1172        assert_eq!(kv.key.as_str(), "πŸ˜€/\u{0}");
1173        assert_eq!(kv.value.as_string(), OptionString::Some(az("v")));
1174    }
1175
1176    // ==================================================================
1177    // copy_from_array  (numeric: zero / min_max / overflow)
1178    // ==================================================================
1179
1180    #[test]
1181    fn json_vec_copy_from_array_null_ptr_is_empty_even_at_usize_max_len() {
1182        // The null check runs first, so a bogus (null, huge) pair from C must
1183        // yield an empty vec rather than constructing a wild slice.
1184        let v = JsonVec::copy_from_array(core::ptr::null(), 0);
1185        assert!(v.is_empty());
1186        let v = JsonVec::copy_from_array(core::ptr::null(), usize::MAX);
1187        assert!(v.is_empty());
1188        assert_eq!(v.len(), 0);
1189    }
1190
1191    #[test]
1192    fn json_vec_copy_from_array_zero_len_with_valid_ptr_is_empty() {
1193        let items = [Json::null(), Json::bool(true)];
1194        let v = JsonVec::copy_from_array(items.as_ptr(), 0);
1195        assert!(v.is_empty());
1196    }
1197
1198    #[test]
1199    fn json_vec_copy_from_array_deep_copies_the_elements() {
1200        let items = vec![
1201            Json::null(),
1202            Json::bool(true),
1203            Json::number(f64::NAN),
1204            Json::string("πŸ˜€"),
1205        ];
1206        let v = JsonVec::copy_from_array(items.as_ptr(), items.len());
1207        assert_eq!(v.len(), 4);
1208        assert_eq!(v.as_slice()[3].as_string(), OptionString::Some(az("πŸ˜€")));
1209        // The copy is independent: dropping the source must not invalidate it.
1210        drop(items);
1211        assert!(v.as_slice()[0].is_null());
1212        assert_eq!(v.as_slice()[1].as_bool(), OptionBool::Some(true));
1213        assert_eq!(v.as_slice()[3].raw_string(), "πŸ˜€");
1214    }
1215
1216    #[test]
1217    fn key_value_vec_copy_from_array_null_ptr_is_empty_even_at_usize_max_len() {
1218        let v = JsonKeyValueVec::copy_from_array(core::ptr::null(), 0);
1219        assert!(v.is_empty());
1220        let v = JsonKeyValueVec::copy_from_array(core::ptr::null(), usize::MAX);
1221        assert!(v.is_empty());
1222        assert_eq!(v.len(), 0);
1223    }
1224
1225    #[test]
1226    fn key_value_vec_copy_from_array_deep_copies_the_elements() {
1227        let items = vec![
1228            JsonKeyValue::create(az("a"), Json::integer(1)),
1229            JsonKeyValue::create(az(""), Json::null()),
1230        ];
1231        let v = JsonKeyValueVec::copy_from_array(items.as_ptr(), items.len());
1232        assert_eq!(v.len(), 2);
1233        let zero_len = JsonKeyValueVec::copy_from_array(items.as_ptr(), 0);
1234        assert!(zero_len.is_empty());
1235        drop(items);
1236        assert_eq!(v.as_slice()[0].key.as_str(), "a");
1237        assert_eq!(v.as_slice()[0].value.as_i64(), OptionI64::Some(1));
1238        assert_eq!(v.as_slice()[1].key.as_str(), "");
1239    }
1240
1241    // ==================================================================
1242    // Json::parse / parse_bytes β€” malformed input
1243    // ==================================================================
1244
1245    #[test]
1246    #[cfg(feature = "serde-json")]
1247    fn parse_empty_and_whitespace_only_input_is_an_error() {
1248        for s in ["", " ", "   ", "\t\n\r", "\u{feff}"] {
1249            let err = Json::parse(s).expect_err("empty/blank input must not parse");
1250            assert!(!err.message.as_str().is_empty());
1251            assert!(Json::parse_bytes(s.as_bytes()).is_err());
1252        }
1253        assert!(Json::parse_bytes(b"").is_err());
1254    }
1255
1256    #[test]
1257    #[cfg(feature = "serde-json")]
1258    fn parse_garbage_returns_err_and_never_panics() {
1259        for s in [
1260            "{", "}", "[", "]", ",", ":", "nul", "tru", "'a'", "{,}", "[,]", "{\"a\"}", "{\"a\":}",
1261            "[1,]", "{\"a\":1,}", "\"unterminated", "\\", "\u{0}", "01", "+1", ".5", "1.", "-",
1262            "0x10", "--1", "1e", "{'a':1}", "undefined",
1263        ] {
1264            assert!(Json::parse(s).is_err(), "{s:?} must be rejected");
1265            assert!(Json::parse_bytes(s.as_bytes()).is_err(), "{s:?} (bytes)");
1266        }
1267    }
1268
1269    #[test]
1270    #[cfg(feature = "serde-json")]
1271    fn parse_leading_and_trailing_junk() {
1272        // Surrounding whitespace is allowed and trimmed...
1273        assert_eq!(Json::parse("  1  ").expect("padded"), Json::integer(1));
1274        assert_eq!(Json::parse("\n\t{}\r\n").expect("padded"), Json::parse("{}").expect("{}"));
1275        // ...but trailing non-whitespace is not.
1276        for s in ["1;garbage", "{} {}", "null null", "1 2", "[1] x"] {
1277            assert!(Json::parse(s).is_err(), "{s:?} must be rejected");
1278        }
1279    }
1280
1281    #[test]
1282    #[cfg(feature = "serde-json")]
1283    fn parse_bytes_rejects_invalid_utf8_without_panicking() {
1284        assert!(Json::parse_bytes(&[0xFF, 0xFE, 0x00]).is_err());
1285        // Structurally valid JSON, but the string body is not UTF-8.
1286        assert!(Json::parse_bytes(&[b'"', 0xFF, b'"']).is_err());
1287        // Lone continuation byte inside an otherwise fine document.
1288        assert!(Json::parse_bytes(&[b'[', 0x80, b']']).is_err());
1289    }
1290
1291    #[test]
1292    #[cfg(feature = "serde-json")]
1293    fn parse_deeply_nested_input_errors_instead_of_overflowing_the_stack() {
1294        // serde_json's 128-level recursion cap turns this into an Err.
1295        let deep = alloc::format!("{}{}", "[".repeat(10_000), "]".repeat(10_000));
1296        assert!(Json::parse(&deep).is_err());
1297        assert!(Json::parse_bytes(deep.as_bytes()).is_err());
1298
1299        let deep_obj = alloc::format!("{}1{}", "{\"a\":".repeat(10_000), "}".repeat(10_000));
1300        assert!(Json::parse(&deep_obj).is_err());
1301
1302        // Unbalanced (never-closing) nesting must also terminate.
1303        let unbalanced = "[".repeat(100_000);
1304        assert!(Json::parse(&unbalanced).is_err());
1305    }
1306
1307    #[test]
1308    #[cfg(feature = "serde-json")]
1309    fn parse_extremely_long_input_terminates() {
1310        const N: usize = 200_000;
1311        let mut doc = String::with_capacity(N * 2 + 2);
1312        doc.push('[');
1313        for i in 0..N {
1314            if i > 0 {
1315                doc.push(',');
1316            }
1317            doc.push('1');
1318        }
1319        doc.push(']');
1320        let j = Json::parse(&doc).expect("a long flat array must parse");
1321        assert!(j.is_array());
1322        assert_eq!(j.len(), N);
1323
1324        // A ~1 MB string payload.
1325        let payload = "a".repeat(1_000_000);
1326        let j = Json::parse(&alloc::format!("\"{payload}\"")).expect("long string");
1327        assert_eq!(j.as_string(), OptionString::Some(AzString::from(payload)));
1328    }
1329
1330    #[test]
1331    #[cfg(feature = "serde-json")]
1332    fn parse_unicode_input() {
1333        let j = Json::parse("\"\u{1F600}\"").expect("emoji");
1334        assert_eq!(j.as_string(), OptionString::Some(az("\u{1F600}")));
1335
1336        // Combining marks + RTL override + escaped NUL survive the round trip.
1337        let j = Json::parse("\"e\\u0301\\u202e\\u0000\"").expect("escapes");
1338        assert_eq!(
1339            j.as_string(),
1340            OptionString::Some(az("e\u{0301}\u{202e}\u{0}"))
1341        );
1342
1343        // Non-ASCII keys.
1344        let j = Json::parse("{\"ΠΊΠ»ΡŽΡ‡\":\"Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅\"}").expect("cyrillic keys");
1345        assert_eq!(
1346            j.get_key("ΠΊΠ»ΡŽΡ‡").expect("key").as_string(),
1347            OptionString::Some(az("Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅"))
1348        );
1349
1350        // A lone surrogate is not encodable as UTF-8 and must be rejected.
1351        assert!(Json::parse("\"\\ud800\"").is_err());
1352    }
1353
1354    #[test]
1355    #[cfg(feature = "serde-json")]
1356    fn parse_boundary_numbers() {
1357        assert_eq!(Json::parse("0").expect("0").as_i64(), OptionI64::Some(0));
1358        // "-0" is accepted; the sign is not observable through as_number().
1359        match Json::parse("-0").expect("-0").as_number() {
1360            OptionF64::Some(v) => assert_eq!(v, 0.0),
1361            OptionF64::None => panic!("-0 must be a number"),
1362        }
1363
1364        // i64::MIN is exactly representable in f64 and reads back exactly.
1365        assert_eq!(
1366            Json::parse("-9223372036854775808").expect("i64::MIN").as_i64(),
1367            OptionI64::Some(i64::MIN)
1368        );
1369        // i64::MAX is NOT: it rounds up to 2^63 on the f64 hop through
1370        // `Number::as_f64()`, so as_i64() reports None (silent precision loss).
1371        let max = Json::parse("9223372036854775807").expect("i64::MAX");
1372        assert_eq!(max.as_number(), OptionF64::Some(two_pow_63()));
1373        assert_eq!(max.as_i64(), OptionI64::None);
1374        // Same for u64::MAX.
1375        assert_eq!(
1376            Json::parse("18446744073709551615").expect("u64::MAX").as_i64(),
1377            OptionI64::None
1378        );
1379
1380        assert!(Json::parse("1e308").expect("1e308").is_number());
1381        assert!(Json::parse("1e-308").expect("1e-308").is_number());
1382
1383        // JSON has no NaN/Infinity literals.
1384        for s in ["NaN", "nan", "Infinity", "-Infinity", "inf"] {
1385            assert!(Json::parse(s).is_err(), "{s:?} is not valid JSON");
1386        }
1387
1388        // Overflowing exponents must not panic; whatever serde decides, the
1389        // result is a deterministic Ok(number) or Err.
1390        if let Ok(j) = Json::parse("1e400") {
1391            assert!(j.is_number());
1392        }
1393        if let Ok(j) = Json::parse("1e-400") {
1394            assert!(j.is_number());
1395        }
1396    }
1397
1398    #[test]
1399    #[cfg(feature = "serde-json")]
1400    fn parse_valid_minimal_inputs() {
1401        assert_eq!(Json::parse("null").expect("null"), Json::null());
1402        assert_eq!(Json::parse("true").expect("true"), Json::bool(true));
1403        assert_eq!(Json::parse("false").expect("false"), Json::bool(false));
1404        assert_eq!(Json::parse("1").expect("1"), Json::integer(1));
1405        assert_eq!(Json::parse("1.5").expect("1.5"), Json::number(1.5));
1406        assert_eq!(Json::parse("\"s\"").expect("str"), Json::string("s"));
1407        assert!(Json::parse("[]").expect("[]").is_array());
1408        assert!(Json::parse("{}").expect("{}").is_object());
1409        // parse_bytes agrees with parse.
1410        assert_eq!(
1411            Json::parse_bytes(b"{\"a\":[1,2]}").expect("bytes"),
1412            Json::parse("{\"a\":[1,2]}").expect("str")
1413        );
1414    }
1415
1416    // ==================================================================
1417    // round trips  (round_trip: representative / edge / stable)
1418    // ==================================================================
1419
1420    #[cfg(feature = "serde-json")]
1421    fn round_trip_corpus() -> Vec<Json> {
1422        vec![
1423            Json::null(),
1424            Json::bool(true),
1425            Json::bool(false),
1426            Json::integer(0),
1427            Json::integer(-1),
1428            Json::integer(i64::MIN),
1429            Json::number(1.5),
1430            Json::number(-0.25),
1431            Json::number(1e21),
1432            Json::string(""),
1433            Json::string("πŸ˜€ \"quoted\" \\slash\\ \n\t \u{0}"),
1434            Json::parse("[]").expect("[]"),
1435            Json::parse("{}").expect("{}"),
1436            Json::parse("[1,[2,[3]],{\"k\":null}]").expect("nested array"),
1437            Json::parse("{\"a\":{\"b\":[1,2,3]},\"ΓΌnΓ―\":\"πŸ˜€\"}").expect("nested object"),
1438        ]
1439    }
1440
1441    #[test]
1442    #[cfg(feature = "serde-json")]
1443    fn parse_of_to_json_string_reproduces_the_value() {
1444        for j in round_trip_corpus() {
1445            let encoded = j.to_json_string();
1446            let decoded = Json::parse(encoded.as_str())
1447                .unwrap_or_else(|e| panic!("{encoded:?} must re-parse: {e}"));
1448            assert_eq!(decoded, j, "round trip failed for {encoded:?}");
1449        }
1450    }
1451
1452    #[test]
1453    #[cfg(feature = "serde-json")]
1454    fn serialize_parse_serialize_is_idempotent() {
1455        for j in round_trip_corpus() {
1456            let once = j.to_json_string();
1457            let twice = Json::parse(once.as_str()).expect("re-parse").to_json_string();
1458            assert_eq!(once.as_str(), twice.as_str());
1459        }
1460    }
1461
1462    #[test]
1463    #[cfg(feature = "serde-json")]
1464    fn round_trip_extreme_floats() {
1465        for n in [f64::MAX, f64::MIN, f64::MIN_POSITIVE, -f64::MIN_POSITIVE] {
1466            let j = Json::number(n);
1467            let encoded = j.to_json_string();
1468            let decoded = Json::parse(encoded.as_str())
1469                .unwrap_or_else(|e| panic!("{encoded:?} must re-parse: {e}"));
1470            assert_eq!(decoded.as_number(), OptionF64::Some(n));
1471        }
1472    }
1473
1474    #[test]
1475    #[cfg(feature = "serde-json")]
1476    fn non_finite_numbers_do_not_survive_to_json_string() {
1477        // BUG (characterized, not fixed here): `to_json_string()` promises valid
1478        // JSON, but for a non-finite `number_value` it falls back to Rust's float
1479        // Display and emits the bare tokens `NaN` / `inf` / `-inf`, which no JSON
1480        // parser accepts. `to_serde_value()` handles the same input correctly by
1481        // mapping it to `null`. Callers must therefore not assume
1482        // `parse(to_json_string(x))` succeeds for a hand-built non-finite number.
1483        for (n, token) in [
1484            (f64::NAN, "NaN"),
1485            (f64::INFINITY, "inf"),
1486            (f64::NEG_INFINITY, "-inf"),
1487        ] {
1488            let j = Json::number(n);
1489            let encoded = j.to_json_string();
1490            assert_eq!(encoded.as_str(), token);
1491            assert!(
1492                Json::parse(encoded.as_str()).is_err(),
1493                "{token} is not valid JSON"
1494            );
1495            // The serde path degrades safely instead.
1496            assert_eq!(j.to_serde_value(), serde_json::Value::Null);
1497        }
1498    }
1499
1500    // ==================================================================
1501    // from_serde_value / to_serde_value
1502    // ==================================================================
1503
1504    #[test]
1505    #[cfg(feature = "serde-json")]
1506    fn from_serde_value_maps_every_variant() {
1507        use serde_json::json;
1508
1509        assert!(Json::from_serde_value(json!(null)).is_null());
1510        assert_eq!(
1511            Json::from_serde_value(json!(true)).as_bool(),
1512            OptionBool::Some(true)
1513        );
1514        assert_eq!(
1515            Json::from_serde_value(json!(-3)).as_i64(),
1516            OptionI64::Some(-3)
1517        );
1518        assert_eq!(
1519            Json::from_serde_value(json!("πŸ˜€")).as_string(),
1520            OptionString::Some(az("πŸ˜€"))
1521        );
1522
1523        let arr = Json::from_serde_value(json!([1, "two", null]));
1524        assert!(arr.is_array());
1525        assert_eq!(arr.len(), 3);
1526        assert_eq!(arr.get_index(1).expect("idx 1"), Json::string("two"));
1527
1528        let obj = Json::from_serde_value(json!({"a": 1, "b": {"c": []}}));
1529        assert!(obj.is_object());
1530        assert_eq!(obj.len(), 2);
1531        assert_eq!(obj.get_key("a").expect("a"), Json::integer(1));
1532        // The serialized payload must itself be valid JSON (invariant).
1533        assert!(Json::parse(obj.raw_string()).is_ok());
1534    }
1535
1536    #[test]
1537    #[cfg(feature = "serde-json")]
1538    fn to_serde_value_round_trips_through_from_serde_value() {
1539        use serde_json::json;
1540
1541        for v in [
1542            json!(null),
1543            json!(false),
1544            json!(0),
1545            json!(-1.5),
1546            json!(""),
1547            json!([]),
1548            json!({}),
1549            json!({"k": [1, {"n": null}], "ΓΌ": "πŸ˜€"}),
1550        ] {
1551            let back = Json::from_serde_value(v.clone()).to_serde_value();
1552            assert_eq!(back, v);
1553        }
1554    }
1555
1556    #[test]
1557    #[cfg(feature = "serde-json")]
1558    fn to_serde_value_on_a_corrupt_container_yields_null() {
1559        assert_eq!(
1560            raw(JsonType::Array, "not json").to_serde_value(),
1561            serde_json::Value::Null
1562        );
1563        assert_eq!(
1564            raw(JsonType::Object, "").to_serde_value(),
1565            serde_json::Value::Null
1566        );
1567    }
1568
1569    // ==================================================================
1570    // Json::array / Json::object  (other: no_panic_smoke)
1571    // ==================================================================
1572
1573    #[test]
1574    #[cfg(feature = "serde-json")]
1575    fn array_constructor_handles_empty_and_non_finite_members() {
1576        let empty = Json::array(JsonVec::new());
1577        assert!(empty.is_array());
1578        assert_eq!(empty.len(), 0);
1579        assert!(empty.is_empty());
1580        assert_eq!(empty.raw_string(), "[]");
1581
1582        // A NaN member cannot be represented in JSON β€” it degrades to null
1583        // (via to_serde_value) rather than producing invalid output or panicking.
1584        let with_nan = Json::array(JsonVec::from_vec(vec![
1585            Json::number(f64::NAN),
1586            Json::number(f64::INFINITY),
1587            Json::integer(1),
1588        ]));
1589        assert_eq!(with_nan.raw_string(), "[null,null,1]");
1590        assert_eq!(with_nan.len(), 3);
1591        assert!(Json::parse(with_nan.raw_string()).is_ok());
1592    }
1593
1594    #[test]
1595    #[cfg(feature = "serde-json")]
1596    fn object_constructor_dedupes_duplicate_keys_last_one_wins() {
1597        let empty = Json::object(JsonKeyValueVec::new());
1598        assert!(empty.is_object());
1599        assert!(empty.is_empty());
1600        assert_eq!(empty.raw_string(), "{}");
1601
1602        let dup = Json::object(JsonKeyValueVec::from_vec(vec![
1603            JsonKeyValue::create(az("k"), Json::integer(1)),
1604            JsonKeyValue::create(az("k"), Json::integer(2)),
1605            JsonKeyValue::create(az(""), Json::null()),
1606        ]));
1607        assert_eq!(dup.len(), 2, "duplicate keys collapse into one entry");
1608        assert_eq!(dup.get_key("k").expect("k"), Json::integer(2));
1609        assert!(dup.get_key("").expect("empty key").is_null());
1610    }
1611
1612    #[test]
1613    #[cfg(feature = "serde-json")]
1614    fn object_constructor_escapes_hostile_keys() {
1615        let obj = Json::object(JsonKeyValueVec::from_vec(vec![JsonKeyValue::create(
1616            az("\"}\nπŸ˜€"),
1617            Json::string("v"),
1618        )]));
1619        // The payload must still be parseable JSON β€” i.e. the key was escaped.
1620        let reparsed = Json::parse(obj.raw_string()).expect("hostile key must be escaped");
1621        assert_eq!(
1622            reparsed.get_key("\"}\nπŸ˜€").expect("key").as_string(),
1623            OptionString::Some(az("v"))
1624        );
1625    }
1626
1627    // ==================================================================
1628    // len / is_empty  (getter + predicate)
1629    // ==================================================================
1630
1631    #[test]
1632    #[cfg(feature = "serde-json")]
1633    fn len_is_zero_for_scalars_which_makes_is_empty_true() {
1634        // Characterization: len()/is_empty() are documented "for arrays/objects";
1635        // for scalars they report 0 / true, so `is_empty()` is NOT "has no value".
1636        for j in [
1637            Json::null(),
1638            Json::bool(true),
1639            Json::integer(7),
1640            Json::string("hello"),
1641        ] {
1642            assert_eq!(j.len(), 0);
1643            assert!(j.is_empty());
1644        }
1645    }
1646
1647    #[test]
1648    #[cfg(feature = "serde-json")]
1649    fn len_of_containers_and_corrupt_payloads() {
1650        assert_eq!(Json::parse("[1,2,3]").expect("arr").len(), 3);
1651        assert_eq!(Json::parse("{\"a\":1}").expect("obj").len(), 1);
1652        assert_eq!(Json::parse("[]").expect("[]").len(), 0);
1653        // Corrupt payload β†’ 0 rather than a panic.
1654        assert_eq!(raw(JsonType::Array, "not json").len(), 0);
1655        assert!(raw(JsonType::Object, "").is_empty());
1656        // Tag/payload mismatch (Array tag over an object payload) β†’ 0.
1657        assert_eq!(raw(JsonType::Array, "{\"a\":1}").len(), 0);
1658    }
1659
1660    // ==================================================================
1661    // get_index / get_key / keys / to_array / to_object
1662    // ==================================================================
1663
1664    #[test]
1665    #[cfg(feature = "serde-json")]
1666    fn get_index_boundaries() {
1667        let arr = Json::parse("[10,20]").expect("arr");
1668        assert_eq!(arr.get_index(0).expect("0"), Json::integer(10));
1669        assert_eq!(arr.get_index(1).expect("1"), Json::integer(20));
1670        assert!(arr.get_index(2).is_none());
1671        assert!(arr.get_index(usize::MAX).is_none());
1672
1673        assert!(Json::parse("[]").expect("[]").get_index(0).is_none());
1674        // Non-arrays never index, whatever the payload says.
1675        assert!(Json::parse("{\"0\":1}").expect("obj").get_index(0).is_none());
1676        assert!(Json::string("abc").get_index(0).is_none());
1677        assert!(raw(JsonType::Array, "not json").get_index(0).is_none());
1678        assert!(raw(JsonType::Array, "{\"a\":1}").get_index(0).is_none());
1679    }
1680
1681    #[test]
1682    #[cfg(feature = "serde-json")]
1683    fn get_key_edge_inputs() {
1684        let obj = Json::parse("{\"\":1,\"a\":null,\"πŸ˜€\":[]}").expect("obj");
1685        assert_eq!(obj.get_key("").expect("empty key"), Json::integer(1));
1686        assert!(obj.get_key("a").expect("a").is_null());
1687        assert!(obj.get_key("πŸ˜€").expect("emoji").is_array());
1688        assert!(obj.get_key("missing").is_none());
1689        // Keys are exact, not prefix/trimmed matches.
1690        assert!(obj.get_key(" a").is_none());
1691        assert!(obj.get_key("A").is_none());
1692        // A huge key must not panic.
1693        assert!(obj.get_key(&"k".repeat(1_000_000)).is_none());
1694        // Non-objects always return None.
1695        assert!(Json::parse("[1]").expect("arr").get_key("0").is_none());
1696        assert!(Json::null().get_key("").is_none());
1697        assert!(raw(JsonType::Object, "not json").get_key("a").is_none());
1698    }
1699
1700    #[test]
1701    #[cfg(feature = "serde-json")]
1702    fn keys_returns_every_key_and_nothing_for_non_objects() {
1703        let obj = Json::parse("{\"b\":1,\"a\":2,\"\":3}").expect("obj");
1704        let keys = obj.keys();
1705        assert_eq!(keys.len(), 3);
1706        for expected in ["a", "b", ""] {
1707            assert!(
1708                keys.iter().any(|k| k.as_str() == expected),
1709                "missing key {expected:?}"
1710            );
1711        }
1712        assert!(Json::parse("{}").expect("{}").keys().is_empty());
1713        assert!(Json::parse("[1,2]").expect("arr").keys().is_empty());
1714        assert!(Json::string("x").keys().is_empty());
1715        assert!(raw(JsonType::Object, "not json").keys().is_empty());
1716    }
1717
1718    #[test]
1719    #[cfg(feature = "serde-json")]
1720    fn to_array_and_to_object_on_wrong_types_and_corrupt_payloads() {
1721        let arr = Json::parse("[null,1]").expect("arr").to_array().expect("to_array");
1722        assert_eq!(arr.len(), 2);
1723        assert!(arr.as_slice()[0].is_null());
1724        assert_eq!(arr.as_slice()[1].as_i64(), OptionI64::Some(1));
1725
1726        let obj = Json::parse("{\"a\":\"v\"}").expect("obj").to_object().expect("to_object");
1727        assert_eq!(obj.len(), 1);
1728        assert_eq!(obj.as_slice()[0].key.as_str(), "a");
1729        assert_eq!(
1730            obj.as_slice()[0].value.as_string(),
1731            OptionString::Some(az("v"))
1732        );
1733
1734        assert!(Json::parse("[]").expect("[]").to_array().expect("empty").is_empty());
1735        assert!(Json::parse("{}").expect("{}").to_object().expect("empty").is_empty());
1736
1737        // Wrong type / corrupt payload / tag mismatch β†’ None, never a panic.
1738        assert!(Json::null().to_array().is_none());
1739        assert!(Json::string("[]").to_array().is_none());
1740        assert!(Json::parse("[]").expect("[]").to_object().is_none());
1741        assert!(raw(JsonType::Array, "not json").to_array().is_none());
1742        assert!(raw(JsonType::Object, "").to_object().is_none());
1743        assert!(raw(JsonType::Array, "{\"a\":1}").to_array().is_none());
1744        assert!(raw(JsonType::Object, "[1]").to_object().is_none());
1745    }
1746
1747    // ==================================================================
1748    // to_json_string / to_string_pretty
1749    // ==================================================================
1750
1751    #[test]
1752    #[cfg(feature = "serde-json")]
1753    fn to_json_string_escapes_strings_unlike_display() {
1754        let j = Json::string("a\"b\nc\\d\u{0}");
1755        let encoded = j.to_json_string();
1756        // Valid JSON that re-parses to the identical value...
1757        assert_eq!(Json::parse(encoded.as_str()).expect("escaped"), j);
1758        // ...and it differs from the (documented as non-JSON) Display output.
1759        assert_ne!(encoded.as_str(), alloc::format!("{j}"));
1760    }
1761
1762    #[test]
1763    #[cfg(feature = "serde-json")]
1764    fn to_string_pretty_matches_to_json_string_for_scalars() {
1765        for j in [
1766            Json::null(),
1767            Json::bool(false),
1768            Json::integer(-7),
1769            Json::number(0.5),
1770            Json::string("πŸ˜€"),
1771        ] {
1772            assert_eq!(j.to_string_pretty().as_str(), j.to_json_string().as_str());
1773        }
1774    }
1775
1776    #[test]
1777    #[cfg(feature = "serde-json")]
1778    fn to_string_pretty_of_containers_reparses_to_the_same_value() {
1779        let j = Json::parse("{\"a\":[1,{\"b\":null}],\"c\":{}}").expect("obj");
1780        let pretty = j.to_string_pretty();
1781        assert!(pretty.as_str().contains('\n'), "pretty output must be indented");
1782        assert_eq!(Json::parse(pretty.as_str()).expect("pretty reparses"), j);
1783
1784        // A corrupt payload is passed through verbatim instead of panicking.
1785        let corrupt = raw(JsonType::Object, "not json");
1786        assert_eq!(corrupt.to_string_pretty().as_str(), "not json");
1787        assert_eq!(raw(JsonType::Array, "").to_string_pretty().as_str(), "");
1788    }
1789
1790    // ==================================================================
1791    // jq / jq_all  (other: no_panic_smoke)
1792    // ==================================================================
1793
1794    #[test]
1795    #[cfg(feature = "serde-json")]
1796    fn jq_on_scalars_only_matches_the_empty_pointer() {
1797        for j in [
1798            Json::null(),
1799            Json::bool(true),
1800            Json::integer(1),
1801            Json::string("s"),
1802        ] {
1803            assert_eq!(j.jq(""), j);
1804            assert!(j.jq("/").is_null());
1805            assert!(j.jq("/a").is_null());
1806            assert!(j.jq("nonsense").is_null());
1807            assert_eq!(j.jq_all("").as_ref().len(), 1);
1808            assert_eq!(j.jq_all("/a").as_ref().len(), 0);
1809        }
1810    }
1811
1812    #[test]
1813    #[cfg(feature = "serde-json")]
1814    fn jq_navigates_and_degrades_to_null() {
1815        let j = Json::parse("{\"a\":{\"b\":[10,20]},\"\":1}").expect("doc");
1816        assert_eq!(j.jq(""), j, "the empty pointer selects the whole document");
1817        assert_eq!(j.jq("/a/b/1"), Json::integer(20));
1818        assert_eq!(j.jq("/"), Json::integer(1), "'/' selects the empty-string key");
1819
1820        // Misses / malformed pointers / hostile input β†’ null, never a panic.
1821        assert!(j.jq("/a/b/2").is_null(), "out-of-range index");
1822        assert!(j.jq("/a/b/-1").is_null(), "negative index is not a usize");
1823        assert!(j.jq("/a/b/99999999999999999999").is_null(), "index overflows usize");
1824        assert!(j.jq("a/b").is_null(), "pointer must start with '/'");
1825        assert!(j.jq("/missing").is_null());
1826        assert!(j.jq(&"/a".repeat(100_000)).is_null(), "huge pointer");
1827        assert!(j.jq("/a/b/1/deeper").is_null(), "descending through a scalar");
1828        assert!(raw(JsonType::Object, "not json").jq("/a").is_null());
1829    }
1830
1831    #[test]
1832    #[cfg(feature = "serde-json")]
1833    fn jq_all_wildcards_and_empty_results() {
1834        let j = Json::parse("{\"a\":[{\"v\":1},{\"v\":2}],\"b\":{\"v\":3},\"c\":7}").expect("doc");
1835
1836        assert_eq!(j.jq_all("/a/*/v").as_ref().len(), 2);
1837        // A wildcard over an object iterates its values; scalars contribute nothing.
1838        assert_eq!(j.jq_all("/*/v").as_ref().len(), 1);
1839        assert_eq!(j.jq_all("/*").as_ref().len(), 3);
1840        assert_eq!(j.jq_all("").as_ref().len(), 1);
1841
1842        // No match / malformed / corrupt β†’ empty vec.
1843        assert_eq!(j.jq_all("/missing/*").as_ref().len(), 0);
1844        assert_eq!(j.jq_all("a").as_ref().len(), 0);
1845        assert_eq!(j.jq_all("/c/*").as_ref().len(), 0, "wildcard over a scalar");
1846        assert_eq!(j.jq_all("/*/*/*/*/*").as_ref().len(), 0);
1847        assert_eq!(
1848            raw(JsonType::Array, "not json").jq_all("/*").as_ref().len(),
1849            0
1850        );
1851
1852        // A pointer that is only wildcards, far longer than the document is deep.
1853        let many = "/*".repeat(10_000);
1854        assert_eq!(j.jq_all(&many).as_ref().len(), 0);
1855    }
1856
1857    // ==================================================================
1858    // jq_all_recursive_depth  (numeric: zero / min_max / overflow)
1859    // ==================================================================
1860
1861    #[test]
1862    #[cfg(feature = "serde-json")]
1863    fn jq_all_recursive_depth_honours_the_wildcard_cap() {
1864        let value = serde_json::json!({"a": 1});
1865
1866        // depth 0 (what jq_all_recursive passes) resolves normally.
1867        assert_eq!(Json::jq_all_recursive_depth(&value, "/a", 0).len(), 1);
1868        // Exactly at the cap it still resolves...
1869        assert_eq!(
1870            Json::jq_all_recursive_depth(&value, "/a", Json::JQ_MAX_WILDCARD_DEPTH).len(),
1871            1
1872        );
1873        // ...one past it, the guard fires and yields no match instead of recursing.
1874        assert_eq!(
1875            Json::jq_all_recursive_depth(&value, "/a", Json::JQ_MAX_WILDCARD_DEPTH + 1).len(),
1876            0
1877        );
1878        // usize::MAX must hit the guard before the `depth + 1` in the wildcard arm,
1879        // so there is no add-overflow panic.
1880        assert_eq!(Json::jq_all_recursive_depth(&value, "/*", usize::MAX).len(), 0);
1881        assert_eq!(Json::jq_all_recursive_depth(&value, "", usize::MAX).len(), 0);
1882    }
1883
1884    #[test]
1885    #[cfg(feature = "serde-json")]
1886    fn jq_all_wildcard_fanout_deeper_than_the_cap_returns_empty() {
1887        // Build the document programmatically: serde_json's own 128-level parse
1888        // cap means such a document can never come from `Json::parse`, so this is
1889        // the only way to drive the wildcard recursion to its 512 limit.
1890        fn nest(depth: usize) -> serde_json::Value {
1891            let mut v = serde_json::Value::from(1_i64);
1892            for _ in 0..depth {
1893                v = serde_json::Value::Array(vec![v]);
1894            }
1895            v
1896        }
1897
1898        // Below the cap: the leaf is found.
1899        let shallow = nest(400);
1900        let found = Json::jq_all_recursive(&shallow, &"/*".repeat(400));
1901        assert_eq!(found.len(), 1);
1902        assert_eq!(found[0].as_i64(), OptionI64::Some(1));
1903
1904        // Above the cap: the guard stops the recursion and returns no match.
1905        let deep = nest(600);
1906        assert!(Json::jq_all_recursive(&deep, &"/*".repeat(600)).is_empty());
1907    }
1908}