extern crate alloc;
use std::borrow::Cow;
use facet_core::{NumericType, PrimitiveType, ScalarType, Type, UserType};
use facet_reflect::{Partial, Span};
use crate::{DeserializeError, DeserializeErrorKind, FormatDeserializer, ScalarValue};
fn number_out_of_range(
value: impl core::fmt::Display,
target_type: &'static str,
) -> DeserializeError {
DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::NumberOutOfRange {
value: value.to_string().into(),
target_type,
},
}
}
fn narrow_int<T, U>(value: U, target_type: &'static str) -> Result<T, DeserializeError>
where
T: TryFrom<U>,
U: Copy + core::fmt::Display,
{
T::try_from(value).map_err(|_| number_out_of_range(value, target_type))
}
#[allow(clippy::result_large_err)]
pub(crate) fn set_scalar_inner<'input, const BORROW: bool>(
mut wip: Partial<'input, BORROW>,
scalar: ScalarValue<'input>,
) -> Result<Partial<'input, BORROW>, SetScalarResult<'input, BORROW>> {
let shape = wip.shape();
let scalar_type = shape.scalar_type();
match scalar {
ScalarValue::Null => {
wip = wip.set_default()?;
}
ScalarValue::Bool(b) => {
wip = wip.set(b)?;
}
ScalarValue::Char(c) => {
wip = wip.set(c)?;
}
ScalarValue::I64(n) => {
match scalar_type {
Some(ScalarType::I8) => wip = wip.set(narrow_int::<i8, _>(n, "i8")?)?,
Some(ScalarType::I16) => wip = wip.set(narrow_int::<i16, _>(n, "i16")?)?,
Some(ScalarType::I32) => wip = wip.set(narrow_int::<i32, _>(n, "i32")?)?,
Some(ScalarType::I64) => wip = wip.set(n)?,
Some(ScalarType::I128) => wip = wip.set(n as i128)?,
Some(ScalarType::ISize) => wip = wip.set(narrow_int::<isize, _>(n, "isize")?)?,
Some(ScalarType::U8) => wip = wip.set(narrow_int::<u8, _>(n, "u8")?)?,
Some(ScalarType::U16) => wip = wip.set(narrow_int::<u16, _>(n, "u16")?)?,
Some(ScalarType::U32) => wip = wip.set(narrow_int::<u32, _>(n, "u32")?)?,
Some(ScalarType::U64) => wip = wip.set(narrow_int::<u64, _>(n, "u64")?)?,
Some(ScalarType::U128) => wip = wip.set(narrow_int::<u128, _>(n, "u128")?)?,
Some(ScalarType::USize) => wip = wip.set(narrow_int::<usize, _>(n, "usize")?)?,
Some(ScalarType::F32) => wip = wip.set(n as f32)?,
Some(ScalarType::F64) => wip = wip.set(n as f64)?,
Some(ScalarType::String) => {
wip = wip.set(alloc::string::ToString::to_string(&n))?
}
_ => wip = wip.set(n)?,
}
}
ScalarValue::U64(n) => {
match scalar_type {
Some(ScalarType::U8) => wip = wip.set(narrow_int::<u8, _>(n, "u8")?)?,
Some(ScalarType::U16) => wip = wip.set(narrow_int::<u16, _>(n, "u16")?)?,
Some(ScalarType::U32) => wip = wip.set(narrow_int::<u32, _>(n, "u32")?)?,
Some(ScalarType::U64) => wip = wip.set(n)?,
Some(ScalarType::U128) => wip = wip.set(n as u128)?,
Some(ScalarType::USize) => wip = wip.set(narrow_int::<usize, _>(n, "usize")?)?,
Some(ScalarType::I8) => wip = wip.set(narrow_int::<i8, _>(n, "i8")?)?,
Some(ScalarType::I16) => wip = wip.set(narrow_int::<i16, _>(n, "i16")?)?,
Some(ScalarType::I32) => wip = wip.set(narrow_int::<i32, _>(n, "i32")?)?,
Some(ScalarType::I64) => wip = wip.set(narrow_int::<i64, _>(n, "i64")?)?,
Some(ScalarType::I128) => wip = wip.set(n as i128)?,
Some(ScalarType::ISize) => wip = wip.set(narrow_int::<isize, _>(n, "isize")?)?,
Some(ScalarType::F32) => wip = wip.set(n as f32)?,
Some(ScalarType::F64) => wip = wip.set(n as f64)?,
Some(ScalarType::String) => {
wip = wip.set(alloc::string::ToString::to_string(&n))?
}
_ => wip = wip.set(n)?,
}
}
ScalarValue::U128(n) => match scalar_type {
Some(ScalarType::U8) => wip = wip.set(narrow_int::<u8, _>(n, "u8")?)?,
Some(ScalarType::U16) => wip = wip.set(narrow_int::<u16, _>(n, "u16")?)?,
Some(ScalarType::U32) => wip = wip.set(narrow_int::<u32, _>(n, "u32")?)?,
Some(ScalarType::U64) => wip = wip.set(narrow_int::<u64, _>(n, "u64")?)?,
Some(ScalarType::U128) => wip = wip.set(n)?,
Some(ScalarType::USize) => wip = wip.set(narrow_int::<usize, _>(n, "usize")?)?,
Some(ScalarType::I8) => wip = wip.set(narrow_int::<i8, _>(n, "i8")?)?,
Some(ScalarType::I16) => wip = wip.set(narrow_int::<i16, _>(n, "i16")?)?,
Some(ScalarType::I32) => wip = wip.set(narrow_int::<i32, _>(n, "i32")?)?,
Some(ScalarType::I64) => wip = wip.set(narrow_int::<i64, _>(n, "i64")?)?,
Some(ScalarType::I128) => wip = wip.set(narrow_int::<i128, _>(n, "i128")?)?,
Some(ScalarType::ISize) => wip = wip.set(narrow_int::<isize, _>(n, "isize")?)?,
Some(ScalarType::F32) => wip = wip.set(n as f32)?,
Some(ScalarType::F64) => wip = wip.set(n as f64)?,
Some(ScalarType::String) => wip = wip.set(alloc::string::ToString::to_string(&n))?,
_ => wip = wip.set(n)?,
},
ScalarValue::I128(n) => match scalar_type {
Some(ScalarType::I8) => wip = wip.set(narrow_int::<i8, _>(n, "i8")?)?,
Some(ScalarType::I16) => wip = wip.set(narrow_int::<i16, _>(n, "i16")?)?,
Some(ScalarType::I32) => wip = wip.set(narrow_int::<i32, _>(n, "i32")?)?,
Some(ScalarType::I64) => wip = wip.set(narrow_int::<i64, _>(n, "i64")?)?,
Some(ScalarType::I128) => wip = wip.set(n)?,
Some(ScalarType::ISize) => wip = wip.set(narrow_int::<isize, _>(n, "isize")?)?,
Some(ScalarType::U8) => wip = wip.set(narrow_int::<u8, _>(n, "u8")?)?,
Some(ScalarType::U16) => wip = wip.set(narrow_int::<u16, _>(n, "u16")?)?,
Some(ScalarType::U32) => wip = wip.set(narrow_int::<u32, _>(n, "u32")?)?,
Some(ScalarType::U64) => wip = wip.set(narrow_int::<u64, _>(n, "u64")?)?,
Some(ScalarType::U128) => wip = wip.set(narrow_int::<u128, _>(n, "u128")?)?,
Some(ScalarType::USize) => wip = wip.set(narrow_int::<usize, _>(n, "usize")?)?,
Some(ScalarType::F32) => wip = wip.set(n as f32)?,
Some(ScalarType::F64) => wip = wip.set(n as f64)?,
Some(ScalarType::String) => wip = wip.set(alloc::string::ToString::to_string(&n))?,
_ => wip = wip.set(n)?,
},
ScalarValue::F64(n) => {
match scalar_type {
Some(ScalarType::F32) => wip = wip.set(n as f32)?,
Some(ScalarType::F64) => wip = wip.set(n)?,
_ if shape.vtable.has_try_from() && shape.inner.is_some() => {
let inner_shape = shape.inner.unwrap();
wip = wip.begin_inner()?;
if inner_shape.is_type::<f32>() {
wip = wip.set(n as f32)?;
} else {
wip = wip.set(n)?;
}
wip = wip.end()?;
}
_ if shape.vtable.has_parse() => {
wip = wip.parse_from_str(&alloc::string::ToString::to_string(&n))?;
}
_ => wip = wip.set(n)?,
}
}
ScalarValue::Str(s) => {
if shape.vtable.has_parse() {
wip = wip.parse_from_str(s.as_ref())?;
} else {
return Err(SetScalarResult::NeedsStringValue { wip, s });
}
}
ScalarValue::Bytes(b) => {
if shape.vtable.has_parse_bytes() {
wip = wip.parse_from_bytes(b.as_ref())?;
} else {
return Err(SetScalarResult::NeedsBytesValue { wip, b });
}
}
ScalarValue::Unit => {
wip = wip.set_default()?;
}
}
Ok(wip)
}
pub(crate) enum SetScalarResult<'input, const BORROW: bool> {
NeedsStringValue {
wip: Partial<'input, BORROW>,
s: Cow<'input, str>,
},
NeedsBytesValue {
wip: Partial<'input, BORROW>,
b: Cow<'input, [u8]>,
},
Error(DeserializeError),
}
impl<'input, const BORROW: bool> From<DeserializeError> for SetScalarResult<'input, BORROW> {
fn from(e: DeserializeError) -> Self {
SetScalarResult::Error(e)
}
}
impl<'input, const BORROW: bool> From<facet_reflect::ReflectError>
for SetScalarResult<'input, BORROW>
{
fn from(e: facet_reflect::ReflectError) -> Self {
SetScalarResult::Error(e.into())
}
}
pub(crate) enum MapKeyTerminalResult<'input, const BORROW: bool> {
NeedsSetString {
wip: Partial<'input, BORROW>,
s: Cow<'input, str>,
},
Error(DeserializeError),
}
impl<'input, const BORROW: bool> From<DeserializeError> for MapKeyTerminalResult<'input, BORROW> {
fn from(e: DeserializeError) -> Self {
MapKeyTerminalResult::Error(e)
}
}
impl<'input, const BORROW: bool> From<facet_reflect::ReflectError>
for MapKeyTerminalResult<'input, BORROW>
{
fn from(e: facet_reflect::ReflectError) -> Self {
MapKeyTerminalResult::Error(e.into())
}
}
#[allow(clippy::result_large_err)]
pub(crate) fn deserialize_map_key_terminal_inner<'input, const BORROW: bool>(
mut wip: Partial<'input, BORROW>,
key: Cow<'input, str>,
span: Span,
) -> Result<Partial<'input, BORROW>, MapKeyTerminalResult<'input, BORROW>> {
let shape = wip.shape();
if let Type::User(UserType::Enum(_)) = &shape.ty {
wip = wip.select_variant_named(&key)?;
return Ok(wip);
}
if let Type::Primitive(PrimitiveType::Numeric(num_ty)) = &shape.ty {
macro_rules! set_parsed_key {
($ty:ty, $expected:literal) => {{
let n: $ty = key.parse().map_err(|_| DeserializeError {
span: Some(span),
path: None,
kind: DeserializeErrorKind::UnexpectedToken {
expected: $expected,
got: alloc::format!("string '{}'", key).into(),
},
})?;
wip = wip.set(n)?;
return Ok(wip);
}};
}
match ScalarType::try_from_shape(shape) {
Some(ScalarType::I8) => set_parsed_key!(i8, "valid integer for map key"),
Some(ScalarType::I16) => set_parsed_key!(i16, "valid integer for map key"),
Some(ScalarType::I32) => set_parsed_key!(i32, "valid integer for map key"),
Some(ScalarType::I64) => set_parsed_key!(i64, "valid integer for map key"),
Some(ScalarType::I128) => set_parsed_key!(i128, "valid integer for map key"),
Some(ScalarType::ISize) => set_parsed_key!(isize, "valid integer for map key"),
Some(ScalarType::U8) => set_parsed_key!(u8, "valid unsigned integer for map key"),
Some(ScalarType::U16) => set_parsed_key!(u16, "valid unsigned integer for map key"),
Some(ScalarType::U32) => set_parsed_key!(u32, "valid unsigned integer for map key"),
Some(ScalarType::U64) => set_parsed_key!(u64, "valid unsigned integer for map key"),
Some(ScalarType::U128) => set_parsed_key!(u128, "valid unsigned integer for map key"),
Some(ScalarType::USize) => {
set_parsed_key!(usize, "valid unsigned integer for map key")
}
Some(ScalarType::F32) => set_parsed_key!(f32, "valid float for map key"),
Some(ScalarType::F64) => set_parsed_key!(f64, "valid float for map key"),
_ => {}
}
match num_ty {
NumericType::Integer { signed } => {
if *signed {
set_parsed_key!(i64, "valid integer for map key")
} else {
set_parsed_key!(u64, "valid unsigned integer for map key")
}
}
NumericType::Float => set_parsed_key!(f64, "valid float for map key"),
_ => {
return Err(DeserializeError {
span: Some(span),
path: None,
kind: DeserializeErrorKind::UnexpectedToken {
expected: "an integer or float numeric type for a map key",
got: alloc::format!("unsupported numeric type for key '{key}'").into(),
},
}
.into());
}
}
}
Err(MapKeyTerminalResult::NeedsSetString { wip, s: key })
}
impl<'parser, 'input, const BORROW: bool> FormatDeserializer<'parser, 'input, BORROW> {
pub(crate) fn set_scalar(
&mut self,
wip: Partial<'input, BORROW>,
scalar: ScalarValue<'input>,
) -> Result<Partial<'input, BORROW>, DeserializeError> {
match set_scalar_inner(wip, scalar) {
Ok(wip) => Ok(wip),
Err(SetScalarResult::NeedsStringValue { wip, s }) => self.set_string_value(wip, s),
Err(SetScalarResult::NeedsBytesValue { wip, b }) => self.set_bytes_value(wip, b),
Err(SetScalarResult::Error(e)) => Err(e),
}
}
pub(crate) fn set_string_value(
&mut self,
wip: Partial<'input, BORROW>,
s: Cow<'input, str>,
) -> Result<Partial<'input, BORROW>, DeserializeError> {
facet_dessert::set_string_value(wip, s, Some(self.last_span)).map_err(|e| match e {
facet_dessert::DessertError::Reflect { error, span } => DeserializeError {
span,
path: Some(error.path),
kind: DeserializeErrorKind::Reflect {
kind: error.kind,
context: "",
},
},
facet_dessert::DessertError::CannotBorrow { message } => DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::CannotBorrow { reason: message },
},
other => DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::CannotBorrow {
reason: Cow::Owned(alloc::format!("dessert error: {other}")),
},
},
})
}
pub(crate) fn set_bytes_value(
&mut self,
wip: Partial<'input, BORROW>,
b: Cow<'input, [u8]>,
) -> Result<Partial<'input, BORROW>, DeserializeError> {
facet_dessert::set_bytes_value(wip, b, Some(self.last_span)).map_err(|e| match e {
facet_dessert::DessertError::Reflect { error, span } => DeserializeError {
span,
path: Some(error.path),
kind: DeserializeErrorKind::Reflect {
kind: error.kind,
context: "",
},
},
facet_dessert::DessertError::CannotBorrow { message } => DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::CannotBorrow { reason: message },
},
other => DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::CannotBorrow {
reason: Cow::Owned(alloc::format!("dessert error: {other}")),
},
},
})
}
}