Closed
Description
A schema like this...
{
"type": "object",
"properties": {
"x": {
"type": "integer",
"format": "uint8",
"minimum": 1,
"default": 1
}
}
}
... turns into code like this...
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct X {
#[serde(default = "defaults::default_u64::<std::num::NonZeroU8, 1>")]
pub x: std::num::NonZeroU8,
}
impl From<&X> for X {
fn from(value: &X) -> Self {
value.clone()
}
}
pub mod defaults {
pub(super) fn default_u64<T, const V: u64>() -> T
where
T: std::convert::TryFrom<u64>,
<T as std::convert::TryFrom<u64>>::Error: std::fmt::Debug,
{
T::try_from(V).unwrap()
}
}
Which is as-intended: defaults::default_u64
is intended to produce the default value that we want.
However!
error[E0277]: the trait bound `NonZeroU8: From<u64>` is not satisfied
The NonZero*
types implement TryFrom
for their corresponding primitive type, but not other primitive types. This appears to be a point of principle: rust-lang/rust#72712 (comment)
So: cute as this would be, we need a different approach. Some options:
- Use some new trait that takes the place of
TryFrom
but has more implementations. This might be kind of annoying because we'd probably dump all this code into themod defaults
by default (no pun intended). - We could generate
default_non_zero_u64
... it would only create a little bit of annoying code to determine which one to use. - We could generate a function for each default. This would be fine, but it's been nice to share the integer implementations
- Parameterize
default_u64
with two types (rather than one) i.e. the output type and an "intermediate type":defaults::default_u64::<NonZeroU8, u8>