use serde::de::DeserializeOwned;
use serde_json::{
Value,
error::Category,
value::RawValue,
};
use crate::{
ErrorPrivacyPolicy,
JsonDecodeError,
JsonDecodeOptions,
JsonTopLevelKind,
internal::lenient_json_normalizer::LenientJsonNormalizer,
};
#[must_use = "a JSON decoder must be used to decode input"]
#[derive(Debug, Clone, Default)]
pub struct LenientJsonDecoder {
normalizer: LenientJsonNormalizer,
}
impl LenientJsonDecoder {
#[inline(always)]
pub const fn new(options: JsonDecodeOptions) -> Self {
Self {
normalizer: LenientJsonNormalizer::new(options),
}
}
#[inline(always)]
#[must_use = "the decoder options should be inspected or retained"]
pub const fn options(&self) -> &JsonDecodeOptions {
self.normalizer.options()
}
pub fn decode<T>(&self, input: &str) -> Result<T, JsonDecodeError>
where
T: DeserializeOwned,
{
let raw_input_bytes = input.len();
let privacy_policy = self.options().error_privacy_policy();
let normalized = self.normalizer.normalize(input)?;
Self::deserialize_normalized(
normalized.as_ref(),
raw_input_bytes,
normalized.len(),
privacy_policy,
)
}
pub fn decode_slice<T>(&self, input: &[u8]) -> Result<T, JsonDecodeError>
where
T: DeserializeOwned,
{
let raw_input_bytes = input.len();
let privacy_policy = self.options().error_privacy_policy();
if let Some(max_input_bytes) = self.options().max_input_bytes()
&& raw_input_bytes > max_input_bytes
{
return Err(JsonDecodeError::input_too_large(
raw_input_bytes,
max_input_bytes,
privacy_policy,
));
}
let input = std::str::from_utf8(input).map_err(|error| {
JsonDecodeError::invalid_utf8(
error,
raw_input_bytes,
privacy_policy,
)
})?;
self.decode(input)
}
#[inline(always)]
pub fn decode_object<T>(&self, input: &str) -> Result<T, JsonDecodeError>
where
T: DeserializeOwned,
{
self.decode_with_top_level(input, JsonTopLevelKind::Object)
}
#[inline(always)]
pub fn decode_array<T>(
&self,
input: &str,
) -> Result<Vec<T>, JsonDecodeError>
where
T: DeserializeOwned,
{
self.decode_with_top_level(input, JsonTopLevelKind::Array)
}
pub fn decode_value(&self, input: &str) -> Result<Value, JsonDecodeError> {
let raw_input_bytes = input.len();
let privacy_policy = self.options().error_privacy_policy();
let normalized = self.normalizer.normalize(input)?;
Self::parse_value(
normalized.as_ref(),
raw_input_bytes,
normalized.len(),
privacy_policy,
)
}
fn decode_with_top_level<T>(
&self,
input: &str,
expected: JsonTopLevelKind,
) -> Result<T, JsonDecodeError>
where
T: DeserializeOwned,
{
let raw_input_bytes = input.len();
let privacy_policy = self.options().error_privacy_policy();
let normalized = self.normalizer.normalize(input)?;
let normalized_input_bytes = normalized.len();
let actual = JsonTopLevelKind::of_normalized_json(normalized.as_ref());
if actual != expected {
Self::validate_json(
normalized.as_ref(),
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)?;
return Err(JsonDecodeError::unexpected_top_level(
expected,
actual,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
));
}
Self::deserialize_normalized(
normalized.as_ref(),
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)
}
#[inline]
fn parse_value(
normalized: &str,
raw_input_bytes: usize,
normalized_input_bytes: usize,
privacy_policy: ErrorPrivacyPolicy,
) -> Result<Value, JsonDecodeError> {
serde_json::from_str(normalized).map_err(|error| {
JsonDecodeError::invalid_json(
error,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)
})
}
#[inline]
fn validate_json(
normalized: &str,
raw_input_bytes: usize,
normalized_input_bytes: usize,
privacy_policy: ErrorPrivacyPolicy,
) -> Result<(), JsonDecodeError> {
let _: &RawValue =
serde_json::from_str(normalized).map_err(|error| {
JsonDecodeError::invalid_json(
error,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)
})?;
Ok(())
}
#[inline]
fn deserialize_normalized<T>(
normalized: &str,
raw_input_bytes: usize,
normalized_input_bytes: usize,
privacy_policy: ErrorPrivacyPolicy,
) -> Result<T, JsonDecodeError>
where
T: DeserializeOwned,
{
serde_json::from_str(normalized).map_err(|error| {
Self::map_decode_error(
normalized,
error,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)
})
}
#[must_use]
fn map_decode_error(
normalized: &str,
error: serde_json::Error,
raw_input_bytes: usize,
normalized_input_bytes: usize,
privacy_policy: ErrorPrivacyPolicy,
) -> JsonDecodeError {
match error.classify() {
Category::Data => match Self::validate_json(
normalized,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
) {
Ok(()) => JsonDecodeError::deserialize(
error,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
),
Err(error) => error,
},
Category::Io | Category::Syntax | Category::Eof => {
JsonDecodeError::invalid_json(
error,
raw_input_bytes,
normalized_input_bytes,
privacy_policy,
)
}
}
}
}