#![doc = include_str!("../README.md")]
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/meilisearch/deserr/main/assets/deserr.ico?raw=true"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/meilisearch/deserr/main/assets/deserr_squared.png?raw=true"
)]
#[cfg(feature = "actix-web")]
pub mod actix_web;
#[cfg(feature = "axum")]
pub mod axum;
pub mod errors;
mod impls;
#[cfg(feature = "serde-cs")]
pub mod serde_cs;
#[cfg(feature = "serde-json")]
pub mod serde_json;
mod value;
extern crate self as deserr;
pub use deserr_internal::Deserr;
pub use value::{IntoValue, Map, Sequence, Value, ValueKind, ValuePointer, ValuePointerRef};
use std::ops::ControlFlow;
pub trait Deserr<E: DeserializeError>: Sized {
fn deserialize_from_value<V: IntoValue>(
value: Value<V>,
location: ValuePointerRef,
) -> Result<Self, E>;
}
pub fn deserialize<Ret, Val, E>(value: Val) -> Result<Ret, E>
where
Ret: Deserr<E>,
Val: IntoValue,
E: DeserializeError,
{
Ret::deserialize_from_value(value.into_value(), ValuePointerRef::Origin)
}
pub trait MergeWithError<T>: Sized {
fn merge(
self_: Option<Self>,
other: T,
merge_location: ValuePointerRef,
) -> ControlFlow<Self, Self>;
}
pub enum ErrorKind<'a, V: IntoValue> {
IncorrectValueKind {
actual: Value<V>,
accepted: &'a [ValueKind],
},
MissingField {
field: &'a str,
},
UnknownKey {
key: &'a str,
accepted: &'a [&'a str],
},
UnknownValue {
value: &'a str,
accepted: &'a [&'a str],
},
BadSequenceLen {
actual: V::Sequence,
expected: usize,
},
Unexpected {
msg: String,
},
}
pub trait DeserializeError: Sized + MergeWithError<Self> {
fn error<V: IntoValue>(
self_: Option<Self>,
error: ErrorKind<V>,
location: ValuePointerRef,
) -> ControlFlow<Self, Self>;
}
#[doc(hidden)]
pub enum FieldState<T> {
Missing,
Err,
Some(T),
}
impl<T> FieldState<T> {
pub fn is_missing(&self) -> bool {
matches!(self, FieldState::Missing)
}
#[track_caller]
pub fn unwrap(self) -> T {
match self {
FieldState::Some(x) => x,
_ => panic!("Unwrapping an empty field state"),
}
}
#[track_caller]
pub fn unwrap_or(self, value: T) -> T {
match self {
FieldState::Some(x) => x,
FieldState::Missing => value,
FieldState::Err => value,
}
}
#[track_caller]
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
FieldState::Some(x) => Ok(x),
FieldState::Missing => Err(err),
FieldState::Err => Err(err),
}
}
pub fn map<U>(self, f: impl Fn(T) -> U) -> FieldState<U> {
match self {
FieldState::Some(x) => FieldState::Some(f(x)),
FieldState::Missing => FieldState::Missing,
FieldState::Err => FieldState::Err,
}
}
}
pub fn take_cf_content<T>(r: ControlFlow<T, T>) -> T {
match r {
ControlFlow::Continue(x) => x,
ControlFlow::Break(x) => x,
}
}