qubit_json/lenient_json_decoder.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the [`LenientJsonDecoder`] type and its public decoding methods.
10//!
11//! Author: Haixing Hu
12
13use serde::de::DeserializeOwned;
14use serde_json::Value;
15
16use crate::{JsonDecodeError, JsonDecodeOptions, JsonTopLevelKind, LenientJsonNormalizer};
17
18/// A configurable JSON decoder for non-fully-trusted text inputs.
19///
20/// `LenientJsonDecoder` applies a small set of predictable normalization rules
21/// before delegating actual parsing and deserialization to `serde_json`.
22///
23/// The decoder itself is stateless aside from its immutable configuration, so a
24/// single instance can be reused across many decoding calls.
25#[derive(Debug, Clone, Default)]
26pub struct LenientJsonDecoder {
27 /// Stores the immutable normalization and decoding configuration used by
28 /// this decoder instance.
29 normalizer: LenientJsonNormalizer,
30}
31
32impl LenientJsonDecoder {
33 /// Creates a decoder with the exact normalization rules in `options`.
34 ///
35 /// Reusing a decoder instance is recommended when multiple inputs should
36 /// follow the same lenient decoding policy.
37 #[must_use]
38 pub const fn new(options: JsonDecodeOptions) -> Self {
39 Self {
40 normalizer: LenientJsonNormalizer::new(options),
41 }
42 }
43
44 /// Returns the immutable options used by this decoder.
45 ///
46 /// This accessor allows callers to inspect the effective configuration
47 /// without cloning the decoder or duplicating the options elsewhere.
48 #[must_use]
49 pub const fn options(&self) -> &JsonDecodeOptions {
50 self.normalizer.options()
51 }
52
53 /// Decodes `input` into the target Rust type `T`.
54 ///
55 /// This method does not constrain the JSON top-level structure. Arrays,
56 /// objects, scalars, and any other JSON value kinds are all allowed as long
57 /// as they can be deserialized into `T`.
58 ///
59 /// The generic type `T` must implement [`DeserializeOwned`], because the
60 /// decoder first builds an owned [`Value`] and then deserializes from it.
61 ///
62 /// # Errors
63 ///
64 /// Returns [`JsonDecodeError`] when the input becomes empty after
65 /// normalization, when the normalized text is not valid JSON, or when the
66 /// parsed JSON value cannot be deserialized into `T`.
67 pub fn decode<T>(&self, input: &str) -> Result<T, JsonDecodeError>
68 where
69 T: DeserializeOwned,
70 {
71 let value = self.decode_value(input)?;
72 serde_json::from_value(value).map_err(JsonDecodeError::deserialize)
73 }
74
75 /// Decodes `input` into a target type `T`, requiring a top-level JSON
76 /// object.
77 ///
78 /// This method is useful for APIs that require a structured object at the
79 /// top level and want an explicit error when an array or scalar is
80 /// received.
81 ///
82 /// # Errors
83 ///
84 /// Returns [`JsonDecodeError`] when the input cannot be normalized into a
85 /// valid JSON value, when the top-level JSON kind is not an object, or
86 /// when the object cannot be deserialized into `T`.
87 pub fn decode_object<T>(&self, input: &str) -> Result<T, JsonDecodeError>
88 where
89 T: DeserializeOwned,
90 {
91 let value = self.decode_value(input)?;
92 self.ensure_top_level(&value, JsonTopLevelKind::Object)?;
93 serde_json::from_value(value).map_err(JsonDecodeError::deserialize)
94 }
95
96 /// Decodes `input` into a `Vec<T>`, requiring a top-level JSON array.
97 ///
98 /// This method should be preferred over [`Self::decode`] when the caller
99 /// wants an explicit top-level array contract instead of relying on the
100 /// target type alone.
101 ///
102 /// # Errors
103 ///
104 /// Returns [`JsonDecodeError`] when the input cannot be normalized into a
105 /// valid JSON value, when the top-level JSON kind is not an array, or when
106 /// the array cannot be deserialized into `Vec<T>`.
107 pub fn decode_array<T>(&self, input: &str) -> Result<Vec<T>, JsonDecodeError>
108 where
109 T: DeserializeOwned,
110 {
111 let value = self.decode_value(input)?;
112 self.ensure_top_level(&value, JsonTopLevelKind::Array)?;
113 serde_json::from_value(value).map_err(JsonDecodeError::deserialize)
114 }
115
116 /// Decodes `input` into a [`serde_json::Value`].
117 ///
118 /// This is the lowest-level public entry point. It exposes the normalized
119 /// and parsed JSON value before any additional type-specific
120 /// deserialization is attempted.
121 ///
122 /// # Errors
123 ///
124 /// Returns [`JsonDecodeError`] when the input is empty after normalization
125 /// or when the normalized text is not valid JSON syntax.
126 pub fn decode_value(&self, input: &str) -> Result<Value, JsonDecodeError> {
127 let normalized = self.normalizer.normalize(input)?;
128 serde_json::from_str(normalized.as_ref()).map_err(JsonDecodeError::invalid_json)
129 }
130
131 /// Verifies that `value` has the top-level kind required by the calling
132 /// public method.
133 fn ensure_top_level(
134 &self,
135 value: &Value,
136 expected: JsonTopLevelKind,
137 ) -> Result<(), JsonDecodeError> {
138 let actual = JsonTopLevelKind::of(value);
139 if actual == expected {
140 Ok(())
141 } else {
142 Err(JsonDecodeError::unexpected_top_level(expected, actual))
143 }
144 }
145}