use crate::DataType;
use crate::Number;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "derive", derive(serde::Serialize, serde::Deserialize))]
pub struct Error {
kind: Box<ErrorKind>,
}
impl Error {
pub fn unexpected(found: Found, expected: Expected) -> Self {
Self {
kind: Box::new(ErrorKind::Unexpected { found, expected }),
}
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn into_kind(self) -> ErrorKind {
*self.kind
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "derive", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive] pub enum ErrorKind {
Unexpected {
found: Found,
expected: Expected,
},
Custom(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &*self.kind {
ErrorKind::Custom(msg) => write!(f, "{msg}"),
ErrorKind::Unexpected { found, expected } => write!(
f,
"failed to deserialize; expected {expected}, found {found}"
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
#[cfg(feature = "serde")]
impl serde::ser::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: fmt::Display,
{
Self {
kind: Box::new(ErrorKind::Custom(msg.to_string())),
}
}
}
#[cfg(feature = "serde")]
impl serde::de::Error for Error {
fn custom<T>(msg: T) -> Self
where
T: fmt::Display,
{
Self {
kind: Box::new(ErrorKind::Custom(msg.to_string())),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "derive", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive] pub enum Expected {
Unit,
Bool,
Char,
String,
StaticStr,
Bytes,
Seq,
Map,
Struct {
name: Option<String>,
typ: Option<DataType>,
},
Enum {
name: Option<String>,
typ: Option<DataType>,
},
Tuple(usize),
Identifier,
I8,
U8,
I16,
U16,
I32,
U32,
F32,
I64,
U64,
F64,
I128,
U128,
}
#[doc(hidden)] impl fmt::Display for Expected {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expected::Unit => write!(f, "a unit"),
Expected::Bool => write!(f, "a boolean"),
Expected::I8 => write!(f, "an 8-bit signed integer"),
Expected::U8 => write!(f, "an 8-bit unsigned integer"),
Expected::I16 => write!(f, "a 16-bit signed integer"),
Expected::U16 => write!(f, "a 16-bit unsigned integer"),
Expected::I32 => write!(f, "a 32-bit signed integer"),
Expected::U32 => write!(f, "a 32-bit unsigned integer"),
Expected::F32 => write!(f, "a 32-bit floating point"),
Expected::I64 => write!(f, "a 64-bit signed integer"),
Expected::U64 => write!(f, "a 64-bit unsigned integer"),
Expected::F64 => write!(f, "a 64-bit floating point"),
Expected::I128 => write!(f, "a 128-bit signed integer"),
Expected::U128 => write!(f, "a 128-bit unsigned integer"),
Expected::Char => write!(f, "a single character"),
Expected::String => write!(f, "a string"),
Expected::StaticStr => write!(f, "a static string slice"),
Expected::Bytes => write!(f, "a byte array"),
Expected::Seq => write!(f, "a sequence"),
Expected::Map => write!(f, "a map"),
Expected::Struct { name, typ } => match (name.as_deref(), typ) {
(None, None) => write!(f, "a struct"),
(None, Some(typ)) => write!(f, "{typ} struct"),
(Some(name), None) => write!(f, "a struct named {name}"),
(Some(name), Some(typ)) => write!(f, "{typ} struct named {name}"),
},
Expected::Enum { name, typ } => match (name.as_deref(), typ) {
(None, None) => write!(f, "an enum variant"),
(None, Some(typ)) => write!(f, "{typ} enum variant"),
(Some(name), None) => write!(f, "an enum variant of {name}"),
(Some(name), Some(typ)) => write!(f, "{typ} enum variant of {name}"),
},
Expected::Tuple(len) => write!(f, "a tuple with {len} elements"),
Expected::Identifier => write!(f, "a struct field name or an enum variant"),
}
}
}
#[doc(hidden)] impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DataType::Unit => write!(f, "a unit"),
DataType::NewType => write!(f, "a newtype"),
DataType::Tuple => write!(f, "a tuple"),
DataType::Struct => write!(f, "an object-like"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "derive", derive(serde::Serialize, serde::Deserialize))]
pub enum Data {
Unit,
NewType(Found),
Tuple(Vec<Found>),
Struct(Vec<(String, Found)>),
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "derive", derive(serde::Serialize, serde::Deserialize))]
pub enum Found {
Unit,
Bool(bool),
Number(Number),
Char(char),
String(String),
Bytes(Vec<u8>),
Seq(Vec<Found>),
Map(Vec<(Found, Found)>),
Option(Option<Box<Found>>),
Struct {
name: String,
data: Box<Data>,
},
Enum {
name: String,
variant: String,
data: Box<Data>,
},
Tuple(Vec<Found>),
Identifier(String),
}
#[doc(hidden)] impl fmt::Display for Found {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Found::Unit => write!(f, "()"),
Found::Bool(v) => write!(f, "{v}"),
Found::Number(v) => match v {
Number::I8(v) => write!(f, "{v}i8"),
Number::U8(v) => write!(f, "{v}u8"),
Number::I16(v) => write!(f, "{v}i16"),
Number::U16(v) => write!(f, "{v}u16"),
Number::I32(v) => write!(f, "{v}i32"),
Number::U32(v) => write!(f, "{v}u32"),
Number::F32(v) => write!(f, "{v}f32"),
Number::I64(v) => write!(f, "{v}i64"),
Number::U64(v) => write!(f, "{v}u64"),
Number::F64(v) => write!(f, "{v}f64"),
Number::I128(v) => write!(f, "{v}i128"),
Number::U128(v) => write!(f, "{v}u128"),
},
Found::Char(v) => write!(f, "'{v}'"),
Found::String(v) => write!(f, "{v:?}"),
Found::Bytes(v) => write!(f, "&{v:?}"),
Found::Seq(v) => {
f.write_str("[")?;
let data = v.iter().map(Self::to_string).collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str("]")
}
Found::Map(v) => {
f.write_str("{ ")?;
let data = v
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(" }")
}
Found::Option(v) => match v {
Some(v) => write!(f, "Some({v})"),
None => write!(f, "None"),
},
Found::Struct { name, data } => match data.as_ref() {
Data::Unit => write!(f, "{name}"),
Data::NewType(v) => write!(f, "{name}({v})"),
Data::Tuple(v) => {
write!(f, "{name}(")?;
let data = v.iter().map(Self::to_string).collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(")")
}
Data::Struct(v) => {
write!(f, "{name} {{ ")?;
let data = v
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(" }")
}
},
Found::Enum {
name,
variant,
data,
} => match data.as_ref() {
Data::Unit => write!(f, "{name}::{variant}"),
Data::NewType(v) => write!(f, "{name}::{variant}({v})"),
Data::Tuple(v) => {
write!(f, "{name}::{variant}(")?;
let data = v.iter().map(Self::to_string).collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(")")
}
Data::Struct(v) => {
write!(f, "{name}::{variant} {{ ")?;
let data = v
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(" }")
}
},
Found::Tuple(v) => {
f.write_str("(")?;
let data = v.iter().map(Self::to_string).collect::<Vec<_>>();
f.write_str(&data.join(", "))?;
f.write_str(")")
}
Found::Identifier(v) => write!(f, "{v}"),
}
}
}