use alloc::{boxed::Box, string::ToString};
use serde::{Deserialize, Deserializer, de::DeserializeOwned};
use serde_json::value::RawValue;
use crate::{Field, FieldError};
#[derive(Clone, Debug, Default)]
pub enum JsonField<T> {
#[default]
Missing,
Valid(T),
Invalid {
raw: Box<RawValue>,
error: FieldError,
},
}
impl<T> PartialEq for JsonField<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Missing, Self::Missing) => true,
(Self::Valid(left), Self::Valid(right)) => left == right,
(
Self::Invalid {
raw: left_raw,
error: left_error,
},
Self::Invalid {
raw: right_raw,
error: right_error,
},
) => invalid_fields_eq(left_raw, left_error, right_raw, right_error),
_ => false,
}
}
}
impl<T> Eq for JsonField<T> where T: Eq {}
impl<T> JsonField<T> {
#[must_use]
pub fn invalid(raw: Box<RawValue>, error: impl Into<FieldError>) -> Self {
Self::Invalid {
raw,
error: error.into(),
}
}
impl_common_field_methods! {
map_return: JsonField<U>;
map_missing: JsonField::Missing;
map_valid: JsonField::Valid;
invalid_ignore: Self::Invalid { .. },
invalid_error: Self::Invalid { error, .. } => error;
invalid_map: Self::Invalid { raw, error } => JsonField::Invalid { raw, error };
into_result_extra: "The raw JSON value is discarded when converting an invalid field into an error.";
}
#[must_use]
pub const fn raw_value(&self) -> Option<&RawValue> {
match self {
Self::Invalid { raw, .. } => Some(raw),
Self::Missing | Self::Valid(_) => None,
}
}
#[must_use]
pub fn raw_json(&self) -> Option<&str> {
self.raw_value().map(RawValue::get)
}
}
impl<T> From<T> for JsonField<T> {
fn from(value: T) -> Self {
Self::Valid(value)
}
}
impl<T> From<JsonField<T>> for Field<T> {
fn from(field: JsonField<T>) -> Self {
match field {
JsonField::Missing => Self::Missing,
JsonField::Valid(value) => Self::Valid(value),
JsonField::Invalid { error, .. } => Self::Invalid(error),
}
}
}
impl<'de, T> Deserialize<'de> for JsonField<T>
where
T: DeserializeOwned,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = Box::<RawValue>::deserialize(deserializer)?;
if raw.get() == "null" {
return Ok(Self::Missing);
}
Ok(match serde_json::from_str(raw.get()) {
Ok(value) => Self::Valid(value),
Err(error) => Self::Invalid {
raw,
error: FieldError::new(error.to_string()),
},
})
}
}
#[derive(Clone, Debug, Default)]
pub enum BorrowedJsonField<'de, T> {
#[default]
Missing,
Valid(T),
Invalid {
raw: &'de RawValue,
error: FieldError,
},
}
impl<'left, 'right, T> PartialEq<BorrowedJsonField<'right, T>> for BorrowedJsonField<'left, T>
where
T: PartialEq,
{
fn eq(&self, other: &BorrowedJsonField<'right, T>) -> bool {
match (self, other) {
(Self::Missing, BorrowedJsonField::Missing) => true,
(Self::Valid(left), BorrowedJsonField::Valid(right)) => left == right,
(
Self::Invalid {
raw: left_raw,
error: left_error,
},
BorrowedJsonField::Invalid {
raw: right_raw,
error: right_error,
},
) => invalid_fields_eq(left_raw, left_error, right_raw, right_error),
_ => false,
}
}
}
impl<T> Eq for BorrowedJsonField<'_, T> where T: Eq {}
impl<'de, T> BorrowedJsonField<'de, T> {
#[must_use]
pub fn invalid(raw: &'de RawValue, error: impl Into<FieldError>) -> Self {
Self::Invalid {
raw,
error: error.into(),
}
}
impl_common_field_methods! {
map_return: BorrowedJsonField<'de, U>;
map_missing: BorrowedJsonField::Missing;
map_valid: BorrowedJsonField::Valid;
invalid_ignore: Self::Invalid { .. },
invalid_error: Self::Invalid { error, .. } => error;
invalid_map: Self::Invalid { raw, error } => BorrowedJsonField::Invalid { raw, error };
into_result_extra: "The borrowed raw JSON value is discarded when converting an invalid field into an error.";
}
#[must_use]
pub const fn raw_value(&self) -> Option<&'de RawValue> {
match self {
Self::Invalid { raw, .. } => Some(*raw),
Self::Missing | Self::Valid(_) => None,
}
}
#[must_use]
pub fn raw_json(&self) -> Option<&'de str> {
self.raw_value().map(RawValue::get)
}
}
impl<T> From<T> for BorrowedJsonField<'_, T> {
fn from(value: T) -> Self {
Self::Valid(value)
}
}
impl<T> From<BorrowedJsonField<'_, T>> for Field<T> {
fn from(field: BorrowedJsonField<'_, T>) -> Self {
match field {
BorrowedJsonField::Missing => Self::Missing,
BorrowedJsonField::Valid(value) => Self::Valid(value),
BorrowedJsonField::Invalid { error, .. } => Self::Invalid(error),
}
}
}
impl<'de: 'a, 'a, T> Deserialize<'de> for BorrowedJsonField<'a, T>
where
T: Deserialize<'a>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = <&'a RawValue>::deserialize(deserializer)?;
if raw.get() == "null" {
return Ok(Self::Missing);
}
Ok(match serde_json::from_str(raw.get()) {
Ok(value) => Self::Valid(value),
Err(error) => Self::Invalid {
raw,
error: FieldError::new(error.to_string()),
},
})
}
}
fn invalid_fields_eq(
left_raw: &RawValue,
left_error: &FieldError,
right_raw: &RawValue,
right_error: &FieldError,
) -> bool {
left_raw.get() == right_raw.get() && left_error == right_error
}