use std::{
any, fmt,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
num::{
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
},
path::PathBuf,
str::FromStr,
};
use serde::{
Serialize,
de::{DeserializeOwned, Error as DeError},
};
use crate::{
de::{DeserializeContext, deserializer::ValueDeserializer},
error::ErrorWithOrigin,
metadata::{BasicTypes, ParamMetadata, TypeDescription},
value::{Value, WithOrigin},
};
pub trait DeserializeParam<T>: fmt::Debug + Send + Sync + 'static {
const EXPECTING: BasicTypes;
#[allow(unused)]
fn describe(&self, description: &mut TypeDescription) {
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin>;
fn serialize_param(&self, param: &T) -> serde_json::Value;
}
#[diagnostic::on_unimplemented(
message = "`{Self}` param cannot be deserialized",
note = "Add #[config(with = _)] attribute to specify deserializer to use",
note = "If `{Self}` is a config, add #[config(nest)] or #[config(flatten)]"
)]
pub trait WellKnown: 'static + Sized {
type Deserializer: DeserializeParam<Self>;
const DE: Self::Deserializer;
}
#[diagnostic::on_unimplemented(
message = "Optional `{Self}` param cannot be deserialized",
note = "Add #[config(with = _)] attribute to specify deserializer to use",
note = "If `{Self}` is a config, add #[config(nest)]",
note = "Embedded options (`Option<Option<_>>`) are not supported as param types"
)]
pub trait WellKnownOption: WellKnown {}
pub trait CustomKnownOption: 'static + Send + Sized {
type OptDeserializer: DeserializeParam<Option<Self>>;
const OPT_DE: Self::OptDeserializer;
}
impl<T: WellKnownOption + Send> CustomKnownOption for T {
type OptDeserializer = Optional<T::Deserializer>;
const OPT_DE: Self::OptDeserializer = Optional(Self::DE);
}
impl<T: WellKnown> DeserializeParam<T> for () {
const EXPECTING: BasicTypes = <T::Deserializer as DeserializeParam<T>>::EXPECTING;
fn describe(&self, description: &mut TypeDescription) {
T::DE.describe(description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin> {
T::DE.deserialize_param(ctx, param)
}
fn serialize_param(&self, param: &T) -> serde_json::Value {
T::DE.serialize_param(param)
}
}
pub struct Serde<const EXPECTING: u8>;
impl<const EXPECTING: u8> fmt::Debug for Serde<EXPECTING> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_tuple("Serde")
.field(&BasicTypes::from_raw(EXPECTING))
.finish()
}
}
impl<T: Serialize + DeserializeOwned, const EXPECTING: u8> DeserializeParam<T>
for Serde<EXPECTING>
{
const EXPECTING: BasicTypes = BasicTypes::from_raw(EXPECTING);
fn describe(&self, _description: &mut TypeDescription) {
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin> {
fn is_likely_large_integer(value: &Value) -> bool {
let Value::Number(num) = value else {
return false;
};
if !num.is_f64() {
return false;
}
#[allow(clippy::cast_precision_loss)] num.as_f64().is_some_and(|num| {
num > u64::MAX as f64 || num < i64::MIN as f64
})
}
let expecting = BasicTypes::from_raw(EXPECTING);
let Some(current_value) = ctx.current_value() else {
return Err(DeError::missing_field(param.name));
};
let deserializer = ValueDeserializer::new(current_value, ctx.de_options);
let type_matches = deserializer.value().is_supported_by(expecting);
if !type_matches {
let tip = if expecting.contains(BasicTypes::INTEGER)
&& expecting.contains(BasicTypes::STRING)
&& is_likely_large_integer(deserializer.value())
{
". Try enclosing the value into a string so that it's not coerced to floating-point"
} else {
""
};
return Err(deserializer.invalid_type(&format!("{expecting}{tip}")));
}
T::deserialize(deserializer)
}
fn serialize_param(&self, param: &T) -> serde_json::Value {
serde_json::to_value(param).expect("failed serializing to JSON")
}
}
impl WellKnown for bool {
type Deserializer = super::Serde![bool];
const DE: Self::Deserializer = super::Serde![bool];
}
impl WellKnownOption for bool {}
impl WellKnown for String {
type Deserializer = super::Serde![str];
const DE: Self::Deserializer = super::Serde![str];
}
impl WellKnownOption for String {}
impl WellKnown for PathBuf {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "filesystem path");
}
impl WellKnownOption for PathBuf {}
impl WellKnown for IpAddr {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "IP address");
}
impl WellKnownOption for IpAddr {}
impl WellKnown for Ipv4Addr {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "IPv4 address");
}
impl WellKnownOption for Ipv4Addr {}
impl WellKnown for Ipv6Addr {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "IPv6 address");
}
impl WellKnownOption for Ipv6Addr {}
impl WellKnown for SocketAddr {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "socket address");
}
impl WellKnownOption for SocketAddr {}
impl WellKnown for SocketAddrV4 {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "v4 socket address");
}
impl WellKnownOption for SocketAddrV4 {}
impl WellKnown for SocketAddrV6 {
type Deserializer = Qualified<super::Serde![str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![str], "v6 socket address");
}
impl WellKnownOption for SocketAddrV6 {}
impl WellKnown for f32 {
type Deserializer = super::Serde![float];
const DE: Self::Deserializer = super::Serde![float];
}
impl WellKnownOption for f32 {}
impl WellKnown for f64 {
type Deserializer = super::Serde![float];
const DE: Self::Deserializer = super::Serde![float];
}
impl WellKnownOption for f64 {}
macro_rules! impl_well_known_int {
($($int:ty),+) => {
$(
impl WellKnown for $int {
type Deserializer = super::Serde![int];
const DE: Self::Deserializer = super::Serde![int];
}
impl WellKnownOption for $int {}
)+
};
}
impl_well_known_int!(u8, i8, u16, i16, u32, i32, u64, i64, usize, isize);
impl WellKnown for u128 {
type Deserializer = super::Serde![int, str];
const DE: Self::Deserializer = super::Serde![int, str];
}
impl WellKnownOption for u128 {}
impl WellKnown for i128 {
type Deserializer = super::Serde![int, str];
const DE: Self::Deserializer = super::Serde![int, str];
}
impl WellKnownOption for i128 {}
macro_rules! impl_well_known_non_zero_int {
($($int:ty),+) => {
$(
impl WellKnown for $int {
type Deserializer = Qualified<super::Serde![int]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![int], "non-zero");
}
impl WellKnownOption for $int {}
)+
};
}
impl_well_known_non_zero_int!(
NonZeroU8,
NonZeroI8,
NonZeroU16,
NonZeroI16,
NonZeroU32,
NonZeroI32,
NonZeroU64,
NonZeroI64,
NonZeroUsize,
NonZeroIsize
);
impl WellKnown for NonZeroU128 {
type Deserializer = Qualified<super::Serde![int, str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![int, str], "non-zero");
}
impl WellKnownOption for NonZeroU128 {}
impl WellKnown for NonZeroI128 {
type Deserializer = Qualified<super::Serde![int, str]>;
const DE: Self::Deserializer = Qualified::new(super::Serde![int, str], "non-zero");
}
impl WellKnownOption for NonZeroI128 {}
impl<T: CustomKnownOption> WellKnown for Option<T> {
type Deserializer = T::OptDeserializer;
const DE: Self::Deserializer = T::OPT_DE;
}
#[derive(Debug)]
pub struct Qualified<De> {
inner: De,
description: &'static str,
}
impl<De> Qualified<De> {
pub const fn new(inner: De, description: &'static str) -> Self {
Self { inner, description }
}
}
impl<T, De> DeserializeParam<T> for Qualified<De>
where
De: DeserializeParam<T>,
{
const EXPECTING: BasicTypes = <De as DeserializeParam<T>>::EXPECTING;
fn describe(&self, description: &mut TypeDescription) {
description.set_details(self.description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin> {
self.inner.deserialize_param(ctx, param)
}
fn serialize_param(&self, param: &T) -> serde_json::Value {
self.inner.serialize_param(param)
}
}
pub struct WithDefault<T, D> {
inner: D,
default: fn() -> T,
}
impl<T: 'static, D: fmt::Debug> fmt::Debug for WithDefault<T, D> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WithDefault")
.field("inner", &self.inner)
.field("type", &any::type_name::<T>())
.finish_non_exhaustive()
}
}
impl<T: 'static, De: DeserializeParam<T>> WithDefault<T, De> {
pub const fn new(inner: De, default: fn() -> T) -> Self {
Self { inner, default }
}
}
impl<T: 'static, De: DeserializeParam<T>> DeserializeParam<T> for WithDefault<T, De> {
const EXPECTING: BasicTypes = De::EXPECTING;
fn describe(&self, description: &mut TypeDescription) {
self.inner.describe(description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin> {
if ctx.current_value().is_some() {
self.inner.deserialize_param(ctx, param)
} else {
Ok((self.default)())
}
}
fn serialize_param(&self, param: &T) -> serde_json::Value {
self.inner.serialize_param(param)
}
}
#[derive(Debug)]
pub struct Optional<De, const AND_THEN: bool = false>(pub De);
impl<De> Optional<De> {
pub const fn map(deserializer: De) -> Self {
Self(deserializer)
}
}
impl<De> Optional<De, true> {
pub const fn and_then(deserializer: De) -> Self {
Self(deserializer)
}
}
fn detect_null(ctx: &DeserializeContext<'_>) -> bool {
let current_value = ctx.current_value().map(|val| &val.inner);
matches!(current_value, None | Some(Value::Null))
}
impl<T, De: DeserializeParam<T>> DeserializeParam<Option<T>> for Optional<De> {
const EXPECTING: BasicTypes = De::EXPECTING;
fn describe(&self, description: &mut TypeDescription) {
self.0.describe(description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<Option<T>, ErrorWithOrigin> {
if detect_null(&ctx) {
return Ok(None);
}
self.0.deserialize_param(ctx, param).map(Some)
}
fn serialize_param(&self, param: &Option<T>) -> serde_json::Value {
if let Some(param) = param {
self.0.serialize_param(param)
} else {
serde_json::Value::Null
}
}
}
impl<T, De> DeserializeParam<Option<T>> for Optional<De, true>
where
De: DeserializeParam<Option<T>>,
{
const EXPECTING: BasicTypes = De::EXPECTING;
fn describe(&self, description: &mut TypeDescription) {
self.0.describe(description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<Option<T>, ErrorWithOrigin> {
if detect_null(&ctx) {
return Ok(None);
}
self.0.deserialize_param(ctx, param)
}
fn serialize_param(&self, param: &Option<T>) -> serde_json::Value {
if param.is_some() {
self.0.serialize_param(param)
} else {
serde_json::Value::Null
}
}
}
#[derive(Debug)]
pub struct OrString<De>(pub De);
impl<T, De> DeserializeParam<T> for OrString<De>
where
T: FromStr,
T::Err: fmt::Display,
De: DeserializeParam<T>,
{
const EXPECTING: BasicTypes = <De as DeserializeParam<T>>::EXPECTING.or(BasicTypes::STRING);
fn describe(&self, description: &mut TypeDescription) {
self.0.describe(description);
}
fn deserialize_param(
&self,
ctx: DeserializeContext<'_>,
param: &'static ParamMetadata,
) -> Result<T, ErrorWithOrigin> {
let Some(WithOrigin {
inner: Value::String(s),
origin,
}) = ctx.current_value()
else {
return self.0.deserialize_param(ctx, param);
};
T::from_str(s.expose()).map_err(|err| {
let err = serde_json::Error::custom(err);
ErrorWithOrigin::json(err, origin.clone())
})
}
fn serialize_param(&self, param: &T) -> serde_json::Value {
self.0.serialize_param(param)
}
}