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