Skip to main content

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}