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}