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    /// Creates a strict decoder around a reusable cumulative session.
110    ///
111    /// # Parameters
112    ///
113    /// * `session` - Cumulative session that receives input and decoded-value
114    ///   charges.
115    ///
116    /// # Returns
117    ///
118    /// A decoder that owns `session` until it is consumed by
119    /// [`Self::into_session`].
120    #[inline]
121    #[must_use]
122    pub const fn new(session: JsonDecodeSession<'budget, R, Q>) -> Self {
123        Self {
124            diagnostic_policy: DiagnosticPolicy::Redacted,
125            engine: JsonDecodeEngine::new(session),
126        }
127    }
128
129    /// Decodes one complete document into a guarded value and rejects duplicate
130    /// keys.
131    ///
132    /// # Parameters
133    ///
134    /// * `input` - Complete UTF-8 JSON document.
135    ///
136    /// # Returns
137    ///
138    /// The protected owned value after input and value accounting succeed.
139    ///
140    /// # Errors
141    ///
142    /// Returns a structured error for invalid UTF-8, syntax, numeric range,
143    /// duplicate keys, or configured resource limits.
144    pub fn decode_value_utf8(
145        &mut self,
146        input: &[u8],
147    ) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
148        self.engine.decode_value_utf8(input, self.diagnostic_policy)
149    }
150
151    /// UTF-8 string form of [`Self::decode_value_utf8`].
152    ///
153    /// # Parameters
154    ///
155    /// * `input` - Complete JSON document text.
156    ///
157    /// # Returns
158    ///
159    /// The protected owned value.
160    ///
161    /// # Errors
162    ///
163    /// Returns a structured error for syntax, numeric range, duplicate keys,
164    /// or configured resource limits.
165    pub fn decode_value_str(
166        &mut self,
167        input: &str,
168    ) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
169        self.decode_value_utf8(input.as_bytes())
170    }
171
172    /// Reads one unique-key document through EOF and decodes it into a guarded
173    /// value.
174    ///
175    /// Reads in bounded chunks, with at most one probe byte beyond an active
176    /// input limit. Accepted bytes remain charged when later validation fails.
177    ///
178    /// # Parameters
179    ///
180    /// * `input` - Byte input read through EOF.
181    ///
182    /// # Type Parameters
183    ///
184    /// * `I` - Byte input type that supplies the complete document.
185    ///
186    /// # Returns
187    ///
188    /// The protected owned value.
189    ///
190    /// # Errors
191    ///
192    /// Returns read, input-budget, UTF-8, syntax, numeric-range, duplicate-key,
193    /// or value-budget failures.
194    pub fn decode_value_input<I: ByteInput + ?Sized>(
195        &mut self,
196        input: &mut I,
197    ) -> Result<SafeJsonValue, JsonDecodeError<R, Q>> {
198        self.engine
199            .decode_value_input(input, self.diagnostic_policy)
200    }
201
202    /// Decodes one document while applying a caller policy to each source
203    /// number.
204    ///
205    /// The callback runs in source order after a number token is syntactically
206    /// complete and before its configured representation range is checked. It
207    /// receives the typed path and borrowed source spelling; its first error
208    /// stops scanning immediately. Object keys must be unique after decoding.
209    /// Side effects performed by the callback are not rolled back if later
210    /// syntax, delimiter, or budget validation fails. The string and input
211    /// forms of this method have the same callback contract.
212    ///
213    /// ```
214    /// use std::cell::Cell;
215    /// use std::convert::Infallible;
216    /// use qubit_json::decode::JsonDecoder;
217    /// use qubit_json::decode::JsonNumberPolicy;
218    /// use qubit_json::decode::JsonValidatedDecodeOptions;
219    ///
220    /// let calls = Cell::new(0);
221    /// let result = JsonDecoder::unlimited().decode_unique_validated_str(
222    ///     "[1,]",
223    ///     &JsonValidatedDecodeOptions::builder().build(),
224    ///     |_, _| {
225    ///         calls.set(calls.get() + 1);
226    ///         Ok::<_, Infallible>(JsonNumberPolicy::Preserve)
227    ///     },
228    /// );
229    /// assert!(result.is_err());
230    /// assert_eq!(calls.get(), 1);
231    /// ```
232    ///
233    /// # Parameters
234    ///
235    /// * `input` - Complete UTF-8 JSON document.
236    /// * `options` - Root, number model, and per-document source-token limits.
237    /// * `number_policy` - Synchronous policy called for each complete number.
238    ///
239    /// # Type Parameters
240    ///
241    /// * `E` - Error type returned by the caller's number policy.
242    /// * `F` - Number policy callback type.
243    ///
244    /// # Returns
245    ///
246    /// The protected owned value after complete scanning and accounting.
247    ///
248    /// # Errors
249    ///
250    /// Returns structured decode errors, callback errors with source offsets,
251    /// exact-safe-integer errors, or validated-limit failures.
252    pub fn decode_unique_validated_utf8<E, F>(
253        &mut self,
254        input: &[u8],
255        options: &JsonValidatedDecodeOptions,
256        number_policy: F,
257    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
258    where
259        F: for<'call> FnMut(
260            &'call [JsonPathSegment],
261            JsonNumberToken<'call>,
262        ) -> Result<JsonNumberPolicy, E>,
263    {
264        self.engine.decode_unique_validated_utf8(
265            input,
266            options,
267            number_policy,
268            self.diagnostic_policy,
269        )
270    }
271
272    /// UTF-8 string form of [`Self::decode_unique_validated_utf8`], with the
273    /// same callback side-effect contract documented there.
274    ///
275    /// # Parameters
276    ///
277    /// * `input` - Complete JSON document text.
278    /// * `options` - Root, number model, and per-document source-token limits.
279    /// * `number_policy` - Synchronous number policy callback.
280    ///
281    /// # Type Parameters
282    ///
283    /// * `E` - Error type returned by the caller's number policy.
284    /// * `F` - Number policy callback type.
285    ///
286    /// # Returns
287    ///
288    /// The protected owned value.
289    ///
290    /// # Errors
291    ///
292    /// Returns decode, callback, exact-safe-integer, or validated-limit errors.
293    pub fn decode_unique_validated_str<E, F>(
294        &mut self,
295        input: &str,
296        options: &JsonValidatedDecodeOptions,
297        number_policy: F,
298    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
299    where
300        F: for<'call> FnMut(
301            &'call [JsonPathSegment],
302            JsonNumberToken<'call>,
303        ) -> Result<JsonNumberPolicy, E>,
304    {
305        self.decode_unique_validated_utf8(input.as_bytes(), options, number_policy)
306    }
307
308    /// Reads a byte input through EOF and applies a source-number policy during
309    /// decoding.
310    ///
311    /// Accepted input bytes remain charged if the callback or later validation
312    /// fails; value charges commit only after the complete document succeeds.
313    /// Callback side effects are not rolled back on failure, as documented for
314    /// [`Self::decode_unique_validated_utf8`].
315    ///
316    /// # Parameters
317    ///
318    /// * `input` - Byte input read through EOF.
319    /// * `options` - Root, number model, and per-document token limits.
320    /// * `number_policy` - Synchronous callback for each source number.
321    ///
322    /// # Type Parameters
323    ///
324    /// * `E` - Error type returned by the caller's number policy.
325    /// * `F` - Number policy callback type.
326    /// * `I` - Byte input type that supplies the complete document.
327    ///
328    /// # Returns
329    ///
330    /// The protected owned value.
331    ///
332    /// # Errors
333    ///
334    /// Returns structured decode, read, callback, exact-integer, or limit
335    /// errors.
336    pub fn decode_unique_validated_input<E, F, I>(
337        &mut self,
338        input: &mut I,
339        options: &JsonValidatedDecodeOptions,
340        number_policy: F,
341    ) -> Result<SafeJsonValue, JsonValidatedDecodeError<E, R, Q>>
342    where
343        I: ByteInput + ?Sized,
344        F: for<'call> FnMut(
345            &'call [JsonPathSegment],
346            JsonNumberToken<'call>,
347        ) -> Result<JsonNumberPolicy, E>,
348    {
349        self.engine.decode_unique_validated_input(
350            input,
351            options,
352            number_policy,
353            self.diagnostic_policy,
354        )
355    }
356
357    /// Decodes one byte input using an explicit integer/fallback number model.
358    ///
359    /// The number model controls whether an integer token outside `i64`/`u64`
360    /// is admitted. With the fallback model, that token is admitted only when
361    /// it converts to finite `f64`. Decimal and exponent forms use the
362    /// finite-float rule in both models.
363    ///
364    /// The resulting representation is produced by Serde for `T` and can
365    /// depend on the active `serde_json` features. For deterministic numeric
366    /// projection, use validated decoding with `JsonNumberPolicy::Preserve`;
367    /// it materializes fallback integers as finite `f64` values.
368    ///
369    /// # Parameters
370    ///
371    /// * `input` - Byte input read through EOF.
372    /// * `model` - Integer representation model for admitted source numbers.
373    ///
374    /// # Type Parameters
375    ///
376    /// * `T` - Owned target type deserialized from the document.
377    /// * `I` - Byte input type that supplies the complete document.
378    ///
379    /// # Returns
380    ///
381    /// The owned value produced by Serde. Its numeric representation follows
382    /// `T` and the active Serde implementation and features.
383    ///
384    /// # Errors
385    ///
386    /// Returns read, UTF-8, syntax, numeric-range, budget, or Serde errors.
387    pub fn decode_input_with_number_model<T, I>(
388        &mut self,
389        input: &mut I,
390        model: JsonDecodeNumberModel,
391    ) -> Result<T, JsonDecodeError<R, Q>>
392    where
393        T: DeserializeOwned,
394        I: ByteInput + ?Sized,
395    {
396        let model = match model {
397            JsonDecodeNumberModel::Integer64 => crate::lexical::JsonNumberModel::Integer64,
398            JsonDecodeNumberModel::Integer64WithFiniteFallback => {
399                crate::lexical::JsonNumberModel::Integer64WithFiniteFallback
400            }
401        };
402        self.engine
403            .decode_input_seed(TypedSeed::new(), input, self.diagnostic_policy, model)
404    }
405
406    /// Returns the configured diagnostic policy without changing the decoder.
407    ///
408    /// # Returns
409    ///
410    /// The policy used when constructing input-derived decode errors.
411    #[inline(always)]
412    #[must_use]
413    pub const fn diagnostic_policy(&self) -> DiagnosticPolicy {
414        self.diagnostic_policy
415    }
416
417    /// Returns the cumulative session for read-only inspection.
418    ///
419    /// The returned reference is borrowed from the decoder and exposes the
420    /// charges accumulated by completed operations.
421    ///
422    /// # Returns
423    ///
424    /// A shared reference to the decoder's cumulative session.
425    #[inline(always)]
426    #[must_use]
427    pub const fn session(&self) -> &JsonDecodeSession<'budget, R, Q> {
428        self.engine.session()
429    }
430
431    /// Returns mutable access to the cumulative session.
432    ///
433    /// Mutating the session changes the limits and accounting state used by
434    /// subsequent operations.
435    ///
436    /// # Returns
437    ///
438    /// A mutable reference tied to the decoder's lifetime.
439    #[inline(always)]
440    #[must_use]
441    pub const fn session_mut(&mut self) -> &mut JsonDecodeSession<'budget, R, Q> {
442        self.engine.session_mut()
443    }
444
445    /// Configures whether input-derived error sources are retained.
446    ///
447    /// The default is [`DiagnosticPolicy::Redacted`]. Selecting
448    /// [`DiagnosticPolicy::Detailed`] may retain source errors containing
449    /// fragments or structural details derived from the input.
450    ///
451    /// # Parameters
452    ///
453    /// * `policy` - Diagnostic retention policy for failures produced by this
454    ///   decoder.
455    ///
456    /// # Returns
457    ///
458    /// The decoder with the requested policy; its existing session is retained.
459    #[inline(always)]
460    #[must_use]
461    pub const fn with_diagnostic_policy(mut self, policy: DiagnosticPolicy) -> Self {
462        self.diagnostic_policy = policy;
463        self
464    }
465
466    /// Consumes the decoder and returns its cumulative session.
467    ///
468    /// This transfers ownership of all accumulated accounting state without
469    /// performing another decode or resetting the session.
470    ///
471    /// # Returns
472    ///
473    /// The session previously owned by this decoder.
474    #[inline(always)]
475    #[must_use]
476    pub fn into_session(self) -> JsonDecodeSession<'budget, R, Q> {
477        self.engine.into_session()
478    }
479
480    /// Decodes one complete JSON string and permits results borrowing `input`.
481    ///
482    /// # Type Parameters
483    ///
484    /// * `T` - Target type deserialized from the complete document.
485    ///
486    /// # Parameters
487    ///
488    /// * `input` - UTF-8 JSON text. The returned value may borrow from it.
489    ///
490    /// # Returns
491    ///
492    /// The deserialized value on success.
493    ///
494    /// # Errors
495    ///
496    /// Returns a structured error when input accounting, UTF-8 validation,
497    /// JSON parsing, or Serde deserialization fails.
498    pub fn decode_str<'de, T>(&mut self, input: &'de str) -> Result<T, JsonDecodeError<R, Q>>
499    where
500        T: Deserialize<'de>,
501    {
502        self.decode_seed_str(TypedSeed::new(), input)
503    }
504
505    /// Decodes one complete UTF-8 JSON byte slice and permits borrowed results.
506    ///
507    /// # Type Parameters
508    ///
509    /// * `T` - Target type deserialized from the complete document.
510    ///
511    /// # Parameters
512    ///
513    /// * `input` - Complete UTF-8 JSON bytes. The returned value may borrow
514    ///   from this slice.
515    ///
516    /// # Returns
517    ///
518    /// The deserialized value on success.
519    ///
520    /// # Errors
521    ///
522    /// Returns a structured error when accounting, UTF-8 validation, JSON
523    /// parsing, or Serde deserialization fails.
524    pub fn decode_utf8<'de, T>(&mut self, input: &'de [u8]) -> Result<T, JsonDecodeError<R, Q>>
525    where
526        T: Deserialize<'de>,
527    {
528        self.decode_seed_utf8(TypedSeed::new(), input)
529    }
530
531    /// Decodes a complete document from an item-oriented byte input through
532    /// EOF.
533    ///
534    /// Without an input-byte limit, the input is read in fixed-size chunks.
535    /// With a limit, each read is bounded by the remaining allowance plus at
536    /// most one probe byte. The probe distinguishes an input ending exactly
537    /// at the limit from an oversized input; it is neither charged nor
538    /// buffered, and cannot be returned to the input source. The complete
539    /// admitted document is buffered in memory because the returned value
540    /// must not borrow from the temporary buffer. Without an input-byte
541    /// limit, this buffering has no implicit size cap.
542    ///
543    /// # Parameters
544    ///
545    /// * `input` - Mutable byte input read through EOF.
546    ///
547    /// # Returns
548    ///
549    /// The owned value deserialized from the complete document.
550    ///
551    /// # Errors
552    ///
553    /// Returns a structured error for read failures, input-budget rejection,
554    /// invalid UTF-8, invalid JSON, or target deserialization failures.
555    ///
556    /// # Type Parameters
557    ///
558    /// * `T` - Owned target type deserialized from the document.
559    /// * `I` - Item-oriented byte input type that supplies the document.
560    pub fn decode_input<T, I>(&mut self, input: &mut I) -> Result<T, JsonDecodeError<R, Q>>
561    where
562        T: DeserializeOwned,
563        I: Input<Item = u8> + ?Sized,
564    {
565        self.engine.decode_input(input, self.diagnostic_policy)
566    }
567
568    /// Decodes a JSON string through a caller-provided Serde seed.
569    ///
570    /// # Type Parameters
571    ///
572    /// * `S` - Seed controlling construction of the decoded value.
573    ///
574    /// # Parameters
575    ///
576    /// * `seed` - Serde seed used to deserialize the document.
577    /// * `input` - Complete JSON text, which the seed may borrow from.
578    ///
579    /// # Returns
580    ///
581    /// The value produced by `seed`.
582    ///
583    /// # Errors
584    ///
585    /// Returns a structured error when accounting, parsing, or seeded
586    /// deserialization fails.
587    pub fn decode_seed_str<'de, S>(
588        &mut self,
589        seed: S,
590        input: &'de str,
591    ) -> Result<S::Value, JsonDecodeError<R, Q>>
592    where
593        S: DeserializeSeed<'de>,
594    {
595        self.decode_seed_utf8(seed, input.as_bytes())
596    }
597
598    /// Decodes a UTF-8 byte slice through a caller-provided Serde seed.
599    ///
600    /// # Type Parameters
601    ///
602    /// * `S` - Seed controlling construction of the decoded value.
603    ///
604    /// # Parameters
605    ///
606    /// * `seed` - Serde seed used to deserialize the document.
607    /// * `input` - Complete UTF-8 JSON bytes, which the seed may borrow from.
608    ///
609    /// # Returns
610    ///
611    /// The value produced by `seed`.
612    ///
613    /// # Errors
614    ///
615    /// Returns a structured error when accounting, UTF-8 validation, parsing,
616    /// or seeded deserialization fails.
617    pub fn decode_seed_utf8<'de, S>(
618        &mut self,
619        seed: S,
620        input: &'de [u8],
621    ) -> Result<S::Value, JsonDecodeError<R, Q>>
622    where
623        S: DeserializeSeed<'de>,
624    {
625        self.engine
626            .decode_seed_utf8(seed, input, self.diagnostic_policy)
627    }
628
629    /// Decodes a unique-key JSON document into an owned target.
630    ///
631    /// The document is first materialized under the strict number contract,
632    /// then exposed as native Serde events even with `arbitrary_precision`.
633    /// Source construction uses the configured value depth budget and has no
634    /// separate fixed container limit. Targets cannot borrow the input, and
635    /// RawValue targets receive reconstructed JSON.
636    ///
637    /// # Type Parameters
638    ///
639    /// * `T` - Owned target type deserialized from the unique-key document.
640    ///
641    /// # Parameters
642    ///
643    /// * `input` - Complete JSON text to decode.
644    ///
645    /// # Returns
646    ///
647    /// The decoded owned value after unique-key validation succeeds.
648    ///
649    /// # Errors
650    ///
651    /// Returns an input, syntax, budget, duplicate-key, construction-depth,
652    /// or target-deserialization error. Value usage commits only on success.
653    pub fn decode_unique_str<T>(&mut self, input: &str) -> Result<T, JsonDecodeError<R, Q>>
654    where
655        T: DeserializeOwned,
656    {
657        self.decode_unique_utf8(input.as_bytes())
658    }
659
660    /// Decodes a unique-key UTF-8 JSON document into an owned target.
661    ///
662    /// See [`Self::decode_unique_str`] for numeric and materialization rules.
663    ///
664    /// # Type Parameters
665    ///
666    /// * `T` - Owned target type deserialized from the unique-key document.
667    ///
668    /// # Parameters
669    ///
670    /// * `input` - Complete UTF-8 JSON bytes to decode.
671    ///
672    /// # Returns
673    ///
674    /// The decoded owned value after unique-key validation succeeds.
675    ///
676    /// # Errors
677    ///
678    /// Returns an input, UTF-8, syntax, budget, materialization, or target
679    /// error.
680    pub fn decode_unique_utf8<T>(&mut self, input: &[u8]) -> Result<T, JsonDecodeError<R, Q>>
681    where
682        T: DeserializeOwned,
683    {
684        self.decode_unique_seed_utf8(TypedSeed::new(), input)
685    }
686
687    /// Decodes unique-key JSON through a seed producing an owned result.
688    ///
689    /// The seed receives native scalar, sequence, and map events from an
690    /// intermediate strict JSON tree. Input and value budgets cover the source
691    /// document. The temporary tree and target can coexist during decoding;
692    /// these lexical budgets are not a precise heap-memory bound.
693    /// Object iteration follows `serde_json::Map` ordering. The target's own
694    /// Serde semantics still apply: use `DuplicateKeyRejectingJsonValue`
695    /// instead of a bare `serde_json::Value` to preserve literal private keys.
696    ///
697    /// # Type Parameters
698    ///
699    /// * `S` - Seed that controls construction of the owned result.
700    /// * `T` - Owned result type produced by `S`.
701    ///
702    /// # Parameters
703    ///
704    /// * `seed` - Serde seed used to deserialize the materialized document.
705    /// * `input` - Complete UTF-8 JSON bytes to decode.
706    ///
707    /// # Returns
708    ///
709    /// The owned value produced by `seed` after unique-key validation.
710    ///
711    /// # Errors
712    ///
713    /// Returns a structured decode error for input admission, invalid syntax,
714    /// duplicate keys, configured value-depth failure, or seed failure.
715    /// Materialization errors retain source coordinates; target errors have
716    /// no original source position and are redacted by default.
717    pub fn decode_unique_seed_utf8<S, T>(
718        &mut self,
719        seed: S,
720        input: &[u8],
721    ) -> Result<T, JsonDecodeError<R, Q>>
722    where
723        S: for<'de> DeserializeSeed<'de, Value = T>,
724    {
725        self.engine
726            .decode_unique_seed_utf8(seed, input, self.diagnostic_policy)
727    }
728
729    /// Decodes a complete JSON string while requiring a top-level object.
730    ///
731    /// The top-level check is performed before the decoded value is committed,
732    /// so an array, scalar, or otherwise valid non-object document is rejected.
733    ///
734    /// # Type Parameters
735    ///
736    /// * `T` - Target type deserialized from the object document.
737    ///
738    /// # Parameters
739    ///
740    /// * `input` - Complete JSON text, which the returned value may borrow.
741    ///
742    /// # Returns
743    ///
744    /// The deserialized object value on success.
745    ///
746    /// # Errors
747    ///
748    /// Returns a structured error for accounting, parsing, top-level-kind, or
749    /// deserialization failures.
750    pub fn decode_object_str<'de, T>(&mut self, input: &'de str) -> Result<T, JsonDecodeError<R, Q>>
751    where
752        T: Deserialize<'de>,
753    {
754        self.decode_object_utf8(input.as_bytes())
755    }
756
757    /// Decodes a complete UTF-8 byte slice while requiring a top-level object.
758    ///
759    /// A syntactically valid array or scalar is rejected by the top-level
760    /// constraint before the decoded value is committed.
761    ///
762    /// # Type Parameters
763    ///
764    /// * `T` - Target type deserialized from the object document.
765    ///
766    /// # Parameters
767    ///
768    /// * `input` - Complete UTF-8 JSON bytes, which the returned value may
769    ///   borrow.
770    ///
771    /// # Returns
772    ///
773    /// The deserialized object value on success.
774    ///
775    /// # Errors
776    ///
777    /// Returns a structured error for accounting, UTF-8 validation, parsing,
778    /// top-level-kind, or deserialization failures.
779    pub fn decode_object_utf8<'de, T>(
780        &mut self,
781        input: &'de [u8],
782    ) -> Result<T, JsonDecodeError<R, Q>>
783    where
784        T: Deserialize<'de>,
785    {
786        self.engine.decode_seed_utf8_with_top_level(
787            TypedSeed::new(),
788            input,
789            self.diagnostic_policy,
790            Some(JsonRootKind::Object),
791        )
792    }
793
794    /// Decodes a complete JSON string while requiring a top-level array.
795    ///
796    /// # Type Parameters
797    ///
798    /// * `T` - Element type deserialized from the array.
799    ///
800    /// # Parameters
801    ///
802    /// * `input` - Complete JSON text, which the returned elements may borrow.
803    ///
804    /// # Returns
805    ///
806    /// The decoded array elements on success.
807    ///
808    /// # Errors
809    ///
810    /// Returns a structured error for accounting, parsing, top-level-kind, or
811    /// deserialization failures.
812    pub fn decode_array_str<'de, T>(
813        &mut self,
814        input: &'de str,
815    ) -> Result<Vec<T>, JsonDecodeError<R, Q>>
816    where
817        T: Deserialize<'de>,
818    {
819        self.decode_array_utf8(input.as_bytes())
820    }
821
822    /// Decodes a complete UTF-8 byte slice while requiring a top-level array.
823    ///
824    /// # Type Parameters
825    ///
826    /// * `T` - Element type deserialized from the array.
827    ///
828    /// # Parameters
829    ///
830    /// * `input` - Complete UTF-8 JSON bytes, which the returned elements may
831    ///   borrow.
832    ///
833    /// # Returns
834    ///
835    /// The decoded array elements on success.
836    ///
837    /// # Errors
838    ///
839    /// Returns a structured error for accounting, UTF-8 validation, parsing,
840    /// top-level-kind, or deserialization failures.
841    pub fn decode_array_utf8<'de, T>(
842        &mut self,
843        input: &'de [u8],
844    ) -> Result<Vec<T>, JsonDecodeError<R, Q>>
845    where
846        T: Deserialize<'de>,
847    {
848        self.engine.decode_seed_utf8_with_top_level(
849            TypedSeed::new(),
850            input,
851            self.diagnostic_policy,
852            Some(JsonRootKind::Array),
853        )
854    }
855
856    /// Validates and accounts for one complete JSON string without
857    /// materializing a target value.
858    ///
859    /// # Parameters
860    ///
861    /// * `input` - Complete JSON text to validate and account for.
862    ///
863    /// # Returns
864    ///
865    /// `Ok(())` after the complete document is valid and accounted for.
866    ///
867    /// # Errors
868    ///
869    /// Returns a structured error when accounting or JSON parsing fails. No
870    /// target value is allocated; `str` input is already valid UTF-8.
871    pub fn validate_str(&mut self, input: &str) -> Result<(), JsonDecodeError<R, Q>> {
872        self.validate_utf8(input.as_bytes())
873    }
874
875    /// Validates and accounts for one complete UTF-8 JSON byte slice without
876    /// materializing a target value.
877    ///
878    /// # Parameters
879    ///
880    /// * `input` - Complete UTF-8 JSON bytes to validate and account for.
881    ///
882    /// # Returns
883    ///
884    /// `Ok(())` after the complete document is valid and accounted for.
885    ///
886    /// # Errors
887    ///
888    /// Returns a structured error when accounting, UTF-8 validation, or JSON
889    /// parsing fails. No target value is allocated.
890    pub fn validate_utf8(&mut self, input: &[u8]) -> Result<(), JsonDecodeError<R, Q>> {
891        self.engine.validate_utf8(input, self.diagnostic_policy)
892    }
893}