Skip to main content

qubit_json/decode/
json_decoder.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Stateful strict JSON decoding with caller-owned resource accounting.
9
10use qubit_budget::ResourceQuantity;
11use qubit_budget::json::JsonDecodeLimits;
12use qubit_budget::json::JsonDecodeSession;
13use qubit_budget::json::JsonResource;
14use qubit_io::ByteInput;
15use qubit_io::Input;
16use serde::Deserialize;
17use serde::de::DeserializeOwned;
18use serde::de::DeserializeSeed;
19
20use super::DiagnosticPolicy;
21use super::JsonDecodeError;
22use super::JsonDecodeNumberModel;
23use super::JsonNumberPolicy;
24use super::JsonNumberToken;
25use super::JsonPathSegment;
26use super::JsonRootKind;
27use super::JsonValidatedDecodeError;
28use super::JsonValidatedDecodeOptions;
29use super::internal::JsonDecodeEngine;
30use super::internal::TypedSeed;
31use crate::value::SafeJsonValue;
32
33/// Strictly decodes complete JSON documents while retaining cumulative usage.
34///
35/// This facade performs no normalization. It accepts integers from `i64::MIN`
36/// through `u64::MAX`, requires finite floating-point values, supports values
37/// borrowing from its input, and exposes caller-provided Serde seeds.
38///
39/// # Type Parameters
40///
41/// * `'budget` - Lifetime of the resource budget borrowed by the decoder's
42///   cumulative session.
43/// * `R` - Resource identity type tracked by the session.
44/// * `Q` - Quantity type used for resource limits and accounting.
45///
46/// # Examples
47///
48/// ```
49/// use qubit_json::decode::JsonDecoder;
50/// use serde_json::Value;
51///
52/// let mut decoder = JsonDecoder::unlimited();
53/// let value = decoder.decode_str::<Value>(r#"{"ok":true}"#)?;
54/// assert_eq!(value["ok"], true);
55/// # Ok::<(), qubit_json::decode::JsonDecodeError>(())
56/// ```
57#[derive(Debug)]
58pub struct JsonDecoder<'budget, R = JsonResource, Q = usize>
59where
60    Q: ResourceQuantity,
61{
62    /// Diagnostic detail retained for input-derived failures.
63    diagnostic_policy: DiagnosticPolicy,
64    /// Shared generic decoding and accounting core.
65    engine: JsonDecodeEngine<'budget, R, Q>,
66}
67
68impl<R, Q> JsonDecoder<'static, R, Q>
69where
70    R: Clone,
71    Q: ResourceQuantity,
72{
73    /// Creates a decoder with a cumulative session built from explicit limits.
74    ///
75    /// # Parameters
76    ///
77    /// * `limits` - Input and decoded-value limits used by the cumulative
78    ///   session.
79    ///
80    /// # Returns
81    ///
82    /// A decoder whose accounting starts empty and is constrained by `limits`.
83    #[inline(always)]
84    #[must_use]
85    pub fn with_limits(limits: JsonDecodeLimits<R, Q>) -> Self {
86        Self::new(JsonDecodeSession::from_limits(limits))
87    }
88}
89
90impl JsonDecoder<'static, JsonResource, usize> {
91    /// Creates a decoder with no configured input or value limits.
92    ///
93    /// # Returns
94    ///
95    /// A decoder using the standard resource identities with all limits
96    /// disabled.
97    #[inline(always)]
98    #[must_use]
99    pub fn unlimited() -> Self {
100        Self::with_limits(JsonDecodeLimits::new())
101    }
102}
103
104impl<'budget, R, Q> JsonDecoder<'budget, R, Q>
105where
106    R: Clone,
107    Q: ResourceQuantity,
108{
109    /// Decodes one complete document into a guarded value and rejects duplicate
110    /// keys.
111    ///
112    /// # Parameters
113    ///
114    /// * `input` - Complete UTF-8 JSON document.
115    ///
116    /// # Returns
117    ///
118    /// The protected owned value after input and value accounting succeed.
119    ///
120    /// # Errors
121    ///
122    /// Returns a structured error for invalid UTF-8, syntax, numeric range,
123    /// duplicate keys, or configured resource limits.
124    pub fn decode_value_utf8(&mut self, input: &[u8]) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
125        self.engine.decode_value_utf8(input, self.diagnostic_policy)
126    }
127
128    /// UTF-8 string form of [`Self::decode_value_utf8`].
129    ///
130    /// # Parameters
131    ///
132    /// * `input` - Complete JSON document text.
133    ///
134    /// # Returns
135    ///
136    /// The protected owned value.
137    ///
138    /// # Errors
139    ///
140    /// Returns a structured error for syntax, numeric range, duplicate keys,
141    /// or configured resource limits.
142    pub fn decode_value_str(&mut self, input: &str) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
143        self.decode_value_utf8(input.as_bytes())
144    }
145
146    /// Reads one unique-key document through EOF and decodes it into a guarded
147    /// value.
148    ///
149    /// Reads in bounded chunks, with at most one probe byte beyond an active
150    /// input limit. Accepted bytes remain charged when later validation fails.
151    ///
152    /// # Parameters
153    ///
154    /// * `input` - Byte input read through EOF.
155    ///
156    /// # Returns
157    ///
158    /// The protected owned value.
159    ///
160    /// # Errors
161    ///
162    /// Returns read, input-budget, UTF-8, syntax, numeric-range, duplicate-key,
163    /// or value-budget failures.
164    pub fn decode_value_input<I: ByteInput + ?Sized>(
165        &mut self,
166        input: &mut I,
167    ) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
168        self.engine.decode_value_input(input, self.diagnostic_policy)
169    }
170
171    /// Decodes one document while applying a caller policy to each source
172    /// number.
173    ///
174    /// The callback runs in source order after a number token is syntactically
175    /// complete and before its configured representation range is checked. It
176    /// receives the typed path and borrowed source spelling; its first error
177    /// stops scanning immediately. Object keys must be unique after decoding.
178    /// Side effects performed by the callback are not rolled back if later
179    /// syntax, delimiter, or budget validation fails. The string and input
180    /// forms of this method have the same callback contract.
181    ///
182    /// ```
183    /// use std::cell::Cell;
184    /// use std::convert::Infallible;
185    /// use qubit_json::decode::JsonDecoder;
186    /// use qubit_json::decode::JsonNumberPolicy;
187    /// use qubit_json::decode::JsonValidatedDecodeOptions;
188    ///
189    /// let calls = Cell::new(0);
190    /// let result = JsonDecoder::unlimited().decode_unique_validated_str(
191    ///     "[1,]",
192    ///     &JsonValidatedDecodeOptions::builder().build(),
193    ///     |_, _| {
194    ///         calls.set(calls.get() + 1);
195    ///         Ok::<_, Infallible>(JsonNumberPolicy::Preserve)
196    ///     },
197    /// );
198    /// assert!(result.is_err());
199    /// assert_eq!(calls.get(), 1);
200    /// ```
201    ///
202    /// # Parameters
203    ///
204    /// * `input` - Complete UTF-8 JSON document.
205    /// * `options` - Root, number model, and per-document source-token limits.
206    /// * `number_policy` - Synchronous policy called for each complete number.
207    ///
208    /// # Returns
209    ///
210    /// The protected owned value after complete scanning and accounting.
211    ///
212    /// # Errors
213    ///
214    /// Returns structured decode errors, callback errors with source offsets,
215    /// exact-safe-integer errors, or validated-limit failures.
216    pub fn decode_unique_validated_utf8<E, F>(
217        &mut self,
218        input: &[u8],
219        options: &JsonValidatedDecodeOptions,
220        number_policy: F,
221    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
222    where
223        F: for<'call> FnMut(&'call [JsonPathSegment], JsonNumberToken<'call>) -> Result<JsonNumberPolicy, E>,
224    {
225        self.engine
226            .decode_unique_validated_utf8(input, options, number_policy, self.diagnostic_policy)
227    }
228
229    /// UTF-8 string form of [`Self::decode_unique_validated_utf8`], with the
230    /// same callback side-effect contract documented there.
231    ///
232    /// # Parameters
233    ///
234    /// * `input` - Complete JSON document text.
235    /// * `options` - Root, number model, and per-document source-token limits.
236    /// * `number_policy` - Synchronous number policy callback.
237    ///
238    /// # Returns
239    ///
240    /// The protected owned value.
241    ///
242    /// # Errors
243    ///
244    /// Returns decode, callback, exact-safe-integer, or validated-limit errors.
245    pub fn decode_unique_validated_str<E, F>(
246        &mut self,
247        input: &str,
248        options: &JsonValidatedDecodeOptions,
249        number_policy: F,
250    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
251    where
252        F: for<'call> FnMut(&'call [JsonPathSegment], JsonNumberToken<'call>) -> Result<JsonNumberPolicy, E>,
253    {
254        self.decode_unique_validated_utf8(input.as_bytes(), options, number_policy)
255    }
256
257    /// Reads a byte input through EOF and applies a source-number policy during
258    /// decoding.
259    ///
260    /// Accepted input bytes remain charged if the callback or later validation
261    /// fails; value charges commit only after the complete document succeeds.
262    /// Callback side effects are not rolled back on failure, as documented for
263    /// [`Self::decode_unique_validated_utf8`].
264    ///
265    /// # Parameters
266    ///
267    /// * `input` - Byte input read through EOF.
268    /// * `options` - Root, number model, and per-document token limits.
269    /// * `number_policy` - Synchronous callback for each source number.
270    ///
271    /// # Returns
272    ///
273    /// The protected owned value.
274    ///
275    /// # Errors
276    ///
277    /// Returns structured decode, read, callback, exact-integer, or limit
278    /// errors.
279    pub fn decode_unique_validated_input<E, F, I>(
280        &mut self,
281        input: &mut I,
282        options: &JsonValidatedDecodeOptions,
283        number_policy: F,
284    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
285    where
286        I: ByteInput + ?Sized,
287        F: for<'call> FnMut(&'call [JsonPathSegment], JsonNumberToken<'call>) -> Result<JsonNumberPolicy, E>,
288    {
289        self.engine
290            .decode_unique_validated_input(input, options, number_policy, self.diagnostic_policy)
291    }
292
293    /// Decodes one byte input using an explicit integer/fallback number model.
294    ///
295    /// The number model controls whether an integer token outside `i64`/`u64`
296    /// is admitted. With the fallback model, that token is admitted only when
297    /// it converts to finite `f64`. Decimal and exponent forms use the
298    /// finite-float rule in both models.
299    ///
300    /// The resulting representation is produced by Serde for `T` and can
301    /// depend on the active `serde_json` features. For deterministic numeric
302    /// projection, use validated decoding with `JsonNumberPolicy::Preserve`;
303    /// it materializes fallback integers as finite `f64` values.
304    ///
305    /// # Parameters
306    ///
307    /// * `input` - Byte input read through EOF.
308    /// * `model` - Integer representation model for admitted source numbers.
309    ///
310    /// # Returns
311    ///
312    /// The owned value produced by Serde. Its numeric representation follows
313    /// `T` and the active Serde implementation and features.
314    ///
315    /// # Errors
316    ///
317    /// Returns read, UTF-8, syntax, numeric-range, budget, or Serde errors.
318    pub fn decode_input_with_number_model<T, I>(
319        &mut self,
320        input: &mut I,
321        model: JsonDecodeNumberModel,
322    ) -> Result<T, JsonDecodeError<R, Q>>
323    where
324        T: DeserializeOwned,
325        I: ByteInput + ?Sized,
326    {
327        let model = match model {
328            JsonDecodeNumberModel::Integer64 => crate::lexical::JsonNumberModel::Integer64,
329            JsonDecodeNumberModel::Integer64WithFiniteFallback => {
330                crate::lexical::JsonNumberModel::Integer64WithFiniteFallback
331            }
332        };
333        self.engine
334            .decode_input_seed(TypedSeed::new(), input, self.diagnostic_policy, model)
335    }
336
337    /// Creates a strict decoder around a reusable cumulative session.
338    ///
339    /// # Parameters
340    ///
341    /// * `session` - Cumulative session that receives input and decoded-value
342    ///   charges.
343    ///
344    /// # Returns
345    ///
346    /// A decoder that owns `session` until it is consumed by
347    /// [`Self::into_session`].
348    #[inline]
349    #[must_use]
350    pub const fn new(session: JsonDecodeSession<'budget, R, Q>) -> Self {
351        Self {
352            diagnostic_policy: DiagnosticPolicy::Redacted,
353            engine: JsonDecodeEngine::new(session),
354        }
355    }
356
357    /// Returns the configured diagnostic policy without changing the decoder.
358    ///
359    /// # Returns
360    ///
361    /// The policy used when constructing input-derived decode errors.
362    #[inline(always)]
363    #[must_use]
364    pub const fn diagnostic_policy(&self) -> DiagnosticPolicy {
365        self.diagnostic_policy
366    }
367
368    /// Returns the cumulative session for read-only inspection.
369    ///
370    /// The returned reference is borrowed from the decoder and exposes the
371    /// charges accumulated by completed operations.
372    ///
373    /// # Returns
374    ///
375    /// A shared reference to the decoder's cumulative session.
376    #[inline(always)]
377    #[must_use]
378    pub const fn session(&self) -> &JsonDecodeSession<'budget, R, Q> {
379        self.engine.session()
380    }
381
382    /// Returns mutable access to the cumulative session.
383    ///
384    /// Mutating the session changes the limits and accounting state used by
385    /// subsequent operations.
386    ///
387    /// # Returns
388    ///
389    /// A mutable reference tied to the decoder's lifetime.
390    #[inline(always)]
391    #[must_use]
392    pub const fn session_mut(&mut self) -> &mut JsonDecodeSession<'budget, R, Q> {
393        self.engine.session_mut()
394    }
395
396    /// Configures whether input-derived error sources are retained.
397    ///
398    /// The default is [`DiagnosticPolicy::Redacted`]. Selecting
399    /// [`DiagnosticPolicy::Detailed`] may retain source errors containing
400    /// fragments or structural details derived from the input.
401    ///
402    /// # Parameters
403    ///
404    /// * `policy` - Diagnostic retention policy for failures produced by this
405    ///   decoder.
406    ///
407    /// # Returns
408    ///
409    /// The decoder with the requested policy; its existing session is retained.
410    #[inline(always)]
411    #[must_use]
412    pub const fn with_diagnostic_policy(mut self, policy: DiagnosticPolicy) -> Self {
413        self.diagnostic_policy = policy;
414        self
415    }
416
417    /// Consumes the decoder and returns its cumulative session.
418    ///
419    /// This transfers ownership of all accumulated accounting state without
420    /// performing another decode or resetting the session.
421    ///
422    /// # Returns
423    ///
424    /// The session previously owned by this decoder.
425    #[inline(always)]
426    #[must_use]
427    pub fn into_session(self) -> JsonDecodeSession<'budget, R, Q> {
428        self.engine.into_session()
429    }
430
431    /// Decodes one complete JSON string and permits results borrowing `input`.
432    ///
433    /// # Type Parameters
434    ///
435    /// * `T` - Target type deserialized from the complete document.
436    ///
437    /// # Parameters
438    ///
439    /// * `input` - UTF-8 JSON text. The returned value may borrow from it.
440    ///
441    /// # Returns
442    ///
443    /// The deserialized value on success.
444    ///
445    /// # Errors
446    ///
447    /// Returns a structured error when input accounting, UTF-8 validation,
448    /// JSON parsing, or Serde deserialization fails.
449    pub fn decode_str<'de, T>(&mut self, input: &'de str) -> Result<T, JsonDecodeError<R, Q>>
450    where
451        T: Deserialize<'de>,
452    {
453        self.decode_seed_str(TypedSeed::new(), input)
454    }
455
456    /// Decodes one complete UTF-8 JSON byte slice and permits borrowed results.
457    ///
458    /// # Type Parameters
459    ///
460    /// * `T` - Target type deserialized from the complete document.
461    ///
462    /// # Parameters
463    ///
464    /// * `input` - Complete UTF-8 JSON bytes. The returned value may borrow
465    ///   from this slice.
466    ///
467    /// # Returns
468    ///
469    /// The deserialized value on success.
470    ///
471    /// # Errors
472    ///
473    /// Returns a structured error when accounting, UTF-8 validation, JSON
474    /// parsing, or Serde deserialization fails.
475    pub fn decode_utf8<'de, T>(&mut self, input: &'de [u8]) -> Result<T, JsonDecodeError<R, Q>>
476    where
477        T: Deserialize<'de>,
478    {
479        self.decode_seed_utf8(TypedSeed::new(), input)
480    }
481
482    /// Decodes a complete document from an item-oriented byte input through
483    /// EOF.
484    ///
485    /// Without an input-byte limit, the input is read in fixed-size chunks.
486    /// With a limit, each read is bounded by the remaining allowance plus at
487    /// most one probe byte. The probe distinguishes an input ending exactly
488    /// at the limit from an oversized input; it is neither charged nor
489    /// buffered, and cannot be returned to the input source. The complete
490    /// admitted document is buffered in memory because the returned value
491    /// must not borrow from the temporary buffer. Without an input-byte
492    /// limit, this buffering has no implicit size cap.
493    ///
494    /// # Parameters
495    ///
496    /// * `input` - Mutable byte input read through EOF.
497    ///
498    /// # Errors
499    ///
500    /// Returns a structured error for read failures, input-budget rejection,
501    /// invalid UTF-8, invalid JSON, or target deserialization failures.
502    pub fn decode_input<T, I>(&mut self, input: &mut I) -> Result<T, JsonDecodeError<R, Q>>
503    where
504        T: DeserializeOwned,
505        I: Input<Item = u8> + ?Sized,
506    {
507        self.engine.decode_input(input, self.diagnostic_policy)
508    }
509
510    /// Decodes a JSON string through a caller-provided Serde seed.
511    ///
512    /// # Type Parameters
513    ///
514    /// * `S` - Seed controlling construction of the decoded value.
515    ///
516    /// # Parameters
517    ///
518    /// * `seed` - Serde seed used to deserialize the document.
519    /// * `input` - Complete JSON text, which the seed may borrow from.
520    ///
521    /// # Returns
522    ///
523    /// The value produced by `seed`.
524    ///
525    /// # Errors
526    ///
527    /// Returns a structured error when accounting, parsing, or seeded
528    /// deserialization fails.
529    pub fn decode_seed_str<'de, S>(&mut self, seed: S, input: &'de str) -> Result<S::Value, JsonDecodeError<R, Q>>
530    where
531        S: DeserializeSeed<'de>,
532    {
533        self.decode_seed_utf8(seed, input.as_bytes())
534    }
535
536    /// Decodes a UTF-8 byte slice through a caller-provided Serde seed.
537    ///
538    /// # Type Parameters
539    ///
540    /// * `S` - Seed controlling construction of the decoded value.
541    ///
542    /// # Parameters
543    ///
544    /// * `seed` - Serde seed used to deserialize the document.
545    /// * `input` - Complete UTF-8 JSON bytes, which the seed may borrow from.
546    ///
547    /// # Returns
548    ///
549    /// The value produced by `seed`.
550    ///
551    /// # Errors
552    ///
553    /// Returns a structured error when accounting, UTF-8 validation, parsing,
554    /// or seeded deserialization fails.
555    pub fn decode_seed_utf8<'de, S>(&mut self, seed: S, input: &'de [u8]) -> Result<S::Value, JsonDecodeError<R, Q>>
556    where
557        S: DeserializeSeed<'de>,
558    {
559        self.engine.decode_seed_utf8(seed, input, self.diagnostic_policy)
560    }
561
562    /// Decodes a unique-key JSON document into an owned target.
563    ///
564    /// The document is first materialized under the strict number contract,
565    /// then exposed as native Serde events even with `arbitrary_precision`.
566    /// Source construction uses the configured value depth budget and has no
567    /// separate fixed container limit. Targets cannot borrow the input, and
568    /// RawValue targets receive reconstructed JSON.
569    ///
570    /// # Errors
571    ///
572    /// Returns an input, syntax, budget, duplicate-key, construction-depth,
573    /// or target-deserialization error. Value usage commits only on success.
574    pub fn decode_unique_str<T>(&mut self, input: &str) -> Result<T, JsonDecodeError<R, Q>>
575    where
576        T: DeserializeOwned,
577    {
578        self.decode_unique_utf8(input.as_bytes())
579    }
580
581    /// Decodes a unique-key UTF-8 JSON document into an owned target.
582    ///
583    /// See [`Self::decode_unique_str`] for numeric and materialization rules.
584    ///
585    /// # Errors
586    ///
587    /// Returns an input, UTF-8, syntax, budget, materialization, or target
588    /// error.
589    pub fn decode_unique_utf8<T>(&mut self, input: &[u8]) -> Result<T, JsonDecodeError<R, Q>>
590    where
591        T: DeserializeOwned,
592    {
593        self.decode_unique_seed_utf8(TypedSeed::new(), input)
594    }
595
596    /// Decodes unique-key JSON through a seed producing an owned result.
597    ///
598    /// The seed receives native scalar, sequence, and map events from an
599    /// intermediate strict JSON tree. Input and value budgets cover the source
600    /// document. The temporary tree and target can coexist during decoding;
601    /// these lexical budgets are not a precise heap-memory bound.
602    /// Object iteration follows `serde_json::Map` ordering. The target's own
603    /// Serde semantics still apply: use `DuplicateKeyRejectingJsonValue`
604    /// instead of a bare `serde_json::Value` to preserve literal private keys.
605    ///
606    /// # Errors
607    ///
608    /// Returns a structured decode error for input admission, invalid syntax,
609    /// duplicate keys, configured value-depth failure, or seed failure.
610    /// Materialization errors retain source coordinates; target errors have
611    /// no original source position and are redacted by default.
612    pub fn decode_unique_seed_utf8<S, T>(&mut self, seed: S, input: &[u8]) -> Result<T, JsonDecodeError<R, Q>>
613    where
614        S: for<'de> DeserializeSeed<'de, Value = T>,
615    {
616        self.engine.decode_unique_seed_utf8(seed, input, self.diagnostic_policy)
617    }
618
619    /// Decodes a complete JSON string while requiring a top-level object.
620    ///
621    /// The top-level check is performed before the decoded value is committed,
622    /// so an array, scalar, or otherwise valid non-object document is rejected.
623    ///
624    /// # Type Parameters
625    ///
626    /// * `T` - Target type deserialized from the object document.
627    ///
628    /// # Parameters
629    ///
630    /// * `input` - Complete JSON text, which the returned value may borrow.
631    ///
632    /// # Returns
633    ///
634    /// The deserialized object value on success.
635    ///
636    /// # Errors
637    ///
638    /// Returns a structured error for accounting, parsing, top-level-kind, or
639    /// deserialization failures.
640    pub fn decode_object_str<'de, T>(&mut self, input: &'de str) -> Result<T, JsonDecodeError<R, Q>>
641    where
642        T: Deserialize<'de>,
643    {
644        self.decode_object_utf8(input.as_bytes())
645    }
646
647    /// Decodes a complete UTF-8 byte slice while requiring a top-level object.
648    ///
649    /// A syntactically valid array or scalar is rejected by the top-level
650    /// constraint before the decoded value is committed.
651    ///
652    /// # Type Parameters
653    ///
654    /// * `T` - Target type deserialized from the object document.
655    ///
656    /// # Parameters
657    ///
658    /// * `input` - Complete UTF-8 JSON bytes, which the returned value may
659    ///   borrow.
660    ///
661    /// # Returns
662    ///
663    /// The deserialized object value on success.
664    ///
665    /// # Errors
666    ///
667    /// Returns a structured error for accounting, UTF-8 validation, parsing,
668    /// top-level-kind, or deserialization failures.
669    pub fn decode_object_utf8<'de, T>(&mut self, input: &'de [u8]) -> Result<T, JsonDecodeError<R, Q>>
670    where
671        T: Deserialize<'de>,
672    {
673        self.engine.decode_seed_utf8_with_top_level(
674            TypedSeed::new(),
675            input,
676            self.diagnostic_policy,
677            Some(JsonRootKind::Object),
678        )
679    }
680
681    /// Decodes a complete JSON string while requiring a top-level array.
682    ///
683    /// # Type Parameters
684    ///
685    /// * `T` - Element type deserialized from the array.
686    ///
687    /// # Parameters
688    ///
689    /// * `input` - Complete JSON text, which the returned elements may borrow.
690    ///
691    /// # Returns
692    ///
693    /// The decoded array elements on success.
694    ///
695    /// # Errors
696    ///
697    /// Returns a structured error for accounting, parsing, top-level-kind, or
698    /// deserialization failures.
699    pub fn decode_array_str<'de, T>(&mut self, input: &'de str) -> Result<Vec<T>, JsonDecodeError<R, Q>>
700    where
701        T: Deserialize<'de>,
702    {
703        self.decode_array_utf8(input.as_bytes())
704    }
705
706    /// Decodes a complete UTF-8 byte slice while requiring a top-level array.
707    ///
708    /// # Type Parameters
709    ///
710    /// * `T` - Element type deserialized from the array.
711    ///
712    /// # Parameters
713    ///
714    /// * `input` - Complete UTF-8 JSON bytes, which the returned elements may
715    ///   borrow.
716    ///
717    /// # Returns
718    ///
719    /// The decoded array elements on success.
720    ///
721    /// # Errors
722    ///
723    /// Returns a structured error for accounting, UTF-8 validation, parsing,
724    /// top-level-kind, or deserialization failures.
725    pub fn decode_array_utf8<'de, T>(&mut self, input: &'de [u8]) -> Result<Vec<T>, JsonDecodeError<R, Q>>
726    where
727        T: Deserialize<'de>,
728    {
729        self.engine.decode_seed_utf8_with_top_level(
730            TypedSeed::new(),
731            input,
732            self.diagnostic_policy,
733            Some(JsonRootKind::Array),
734        )
735    }
736
737    /// Validates and accounts for one complete JSON string without
738    /// materializing a target value.
739    ///
740    /// # Parameters
741    ///
742    /// * `input` - Complete JSON text to validate and account for.
743    ///
744    /// # Returns
745    ///
746    /// `Ok(())` after the complete document is valid and accounted for.
747    ///
748    /// # Errors
749    ///
750    /// Returns a structured error when accounting or JSON parsing fails. No
751    /// target value is allocated; `str` input is already valid UTF-8.
752    pub fn validate_str(&mut self, input: &str) -> Result<(), JsonDecodeError<R, Q>> {
753        self.validate_utf8(input.as_bytes())
754    }
755
756    /// Validates and accounts for one complete UTF-8 JSON byte slice without
757    /// materializing a target value.
758    ///
759    /// # Parameters
760    ///
761    /// * `input` - Complete UTF-8 JSON bytes to validate and account for.
762    ///
763    /// # Returns
764    ///
765    /// `Ok(())` after the complete document is valid and accounted for.
766    ///
767    /// # Errors
768    ///
769    /// Returns a structured error when accounting, UTF-8 validation, or JSON
770    /// parsing fails. No target value is allocated.
771    pub fn validate_utf8(&mut self, input: &[u8]) -> Result<(), JsonDecodeError<R, Q>> {
772        self.engine.validate_utf8(input, self.diagnostic_policy)
773    }
774}