Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from jonasbb:master #48

Merged
merged 10 commits into from
Mar 8, 2024
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ trivial_casts = "warn"
trivial_numeric_casts = "warn"
unused_extern_crates = "warn"
unused_import_braces = "warn"
unused_qualifications = "warn"
# Causes problems with the darling derives in the serde_with_macros crate.
# unused_qualifications = "warn"
variant_size_differences = "warn"
# Unsafe code is needed for array initialization using MaybeUninit.
# unsafe_code = "forbid"
Expand All @@ -49,7 +50,7 @@ cloned_instead_of_copied = "warn"
default_trait_access = "warn"
# Checks for the presence of `_`, `::` or camel-case words outside ticks in documentation.
# Disabled due to FP: https://github.com/rust-lang/rust-clippy/issues/12075
# doc_markdown = "warn"
doc_markdown = "warn"
# Checks for closures which only invoke a method on the closure argument and can be replaced by referencing the method directly.
redundant_closure_for_method_calls = "warn"
semicolon_if_nothing_returned = "warn"
Expand Down
5 changes: 5 additions & 0 deletions serde_with/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

* Implement `JsonSchemaAs` for `EnumMap` by @swlynch99 (#697)

### Fixed

* Detect conflicting `schema_with` attributes on fields with `schemars` annotations by @swlynch99 (#715)
This extends the existing avoidance mechanism to a new variant fixing #712.

## [3.6.1] - 2024-02-08

### Changed
Expand Down
4 changes: 2 additions & 2 deletions serde_with/src/de/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ where
utils::array_from_iterator(
utils::SeqIter::new(seq).map(
|res: Result<DeserializeAsWrap<T, As>, A::Error>| {
res.map(de::DeserializeAsWrap::into_inner)
res.map(DeserializeAsWrap::into_inner)
},
),
&self,
Expand Down Expand Up @@ -1298,7 +1298,7 @@ impl<'de> DeserializeAs<'de, Box<[u8]>> for Bytes {
D: Deserializer<'de>,
{
<Bytes as DeserializeAs<'de, Vec<u8>>>::deserialize_as(deserializer)
.map(alloc::vec::Vec::into_boxed_slice)
.map(Vec::into_boxed_slice)
}
}

Expand Down
1 change: 1 addition & 0 deletions serde_with/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ pub mod json;
mod key_value_map;
pub mod rust;
#[cfg(feature = "schemars_0_8")]
#[cfg_attr(docsrs, doc(cfg(feature = "schemars_0_8")))]
pub mod schemars_0_8;
pub mod ser;
#[cfg(feature = "std")]
Expand Down
2 changes: 1 addition & 1 deletion serde_with/src/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,5 +708,5 @@ pub mod maps_first_key_wins {
pub fn deserialize_ignore_any<'de, D: Deserializer<'de>, T: Default>(
deserializer: D,
) -> Result<T, D::Error> {
serde::de::IgnoredAny::deserialize(deserializer).map(|_| T::default())
IgnoredAny::deserialize(deserializer).map(|_| T::default())
}
17 changes: 13 additions & 4 deletions serde_with/src/schemars_0_8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! This module is only available if using the `schemars_0_8` feature of the crate.
//!
//! If you would like to add support for schemars to your own serde_with helpers
//! If you would like to add support for schemars to your own `serde_with` helpers
//! see [`JsonSchemaAs`].

use crate::{
Expand Down Expand Up @@ -492,6 +492,15 @@ impl<T, U: JsonSchema> JsonSchemaAs<T> for TryFromIntoRef<U> {
forward_schema!(U);
}

impl<T, TA, FA> JsonSchemaAs<T> for IfIsHumanReadable<TA, FA>
where
TA: JsonSchemaAs<T>,
{
// serde_json always has `is_human_readable` set to true so we just use the
// schema for the human readable variant.
forward_schema!(WrapSchema<T, TA>);
}

macro_rules! schema_for_map {
($type:ty) => {
impl<K, V, KA, VA> JsonSchemaAs<$type> for Map<KA, VA>
Expand Down Expand Up @@ -623,7 +632,7 @@ where
)
}

fn json_schema(gen: &mut ::schemars_0_8::gen::SchemaGenerator) -> Schema {
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let schema = <WrapSchema<T, TA> as JsonSchema>::json_schema(gen);
let mut schema = schema.into_object();

Expand Down Expand Up @@ -758,9 +767,9 @@ mod timespan {

use self::timespan::{TimespanSchemaTarget, TimespanTargetType};

/// Internal type used for the base impls on DurationXXX and TimestampYYY types.
/// Internal type used for the base impls on `DurationXXX` and `TimestampYYY` types.
///
/// This allows the JsonSchema impls that are Strict to be generic without
/// This allows the `JsonSchema` impls that are Strict to be generic without
/// committing to it as part of the public API.
struct Timespan<Format, Strictness>(PhantomData<(Format, Strictness)>);

Expand Down
6 changes: 3 additions & 3 deletions serde_with/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ pub(crate) fn duration_signed_from_secs_f64(secs: f64) -> Result<DurationSigned,
if nanos >= MAX_NANOS_F64 {
return Err("overflow when converting float to duration");
}
let mut sign = self::duration::Sign::Positive;
let mut sign = Sign::Positive;
if nanos < 0.0 {
nanos = -nanos;
sign = self::duration::Sign::Negative;
sign = Sign::Negative;
}
let nanos = nanos as u128;
Ok(self::duration::DurationSigned::new(
Ok(DurationSigned::new(
sign,
(nanos / (NANOS_PER_SEC as u128)) as u64,
(nanos % (NANOS_PER_SEC as u128)) as u32,
Expand Down
48 changes: 48 additions & 0 deletions serde_with/tests/schemars_0_8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,41 @@ fn schemars_custom_with() {
}));
}

#[test]
fn schemars_custom_schema_with() {
fn custom_int(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
use schemars::schema::*;

SchemaObject {
instance_type: Some(InstanceType::Integer.into()),
..Default::default()
}
.into()
}

#[serde_as]
#[derive(JsonSchema, Serialize)]
struct Test {
#[serde_as(as = "DisplayFromStr")]
#[schemars(schema_with = "custom_int")]
custom: i32,

#[serde_as(as = "DisplayFromStr")]
#[cfg_attr(any(), schemars(schema_with = "custom_int"))]
with_disabled: i32,

#[serde_as(as = "DisplayFromStr")]
#[cfg_attr(all(), schemars(schema_with = "custom_int"))]
always_enabled: i32,
}

check_matches_schema::<Test>(&json!({
"custom": 3,
"with_disabled": "5",
"always_enabled": 7,
}));
}

mod test_std {
use super::*;
use std::collections::{BTreeMap, VecDeque};
Expand Down Expand Up @@ -670,6 +705,19 @@ fn test_map() {
});
}

#[test]
fn test_if_is_human_readable() {
#[serde_as]
#[derive(Serialize, JsonSchema)]
struct Test {
#[serde_as(as = "IfIsHumanReadable<DisplayFromStr>")]
data: i32,
}

check_valid_json_schema(&Test { data: 5 });
check_matches_schema::<Test>(&json!({ "data": "5" }));
}

#[test]
fn test_set_last_value_wins_with_duplicates() {
#[serde_as]
Expand Down
5 changes: 5 additions & 0 deletions serde_with_macros/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Fixed

* Detect conflicting `schema_with` attributes on fields with `schemars` annotations by @swlynch99 (#715)
This extends the existing avoidance mechanism to a new variant fixing #712.

## [3.6.1] - 2024-02-08

No changes.
Expand Down
18 changes: 11 additions & 7 deletions serde_with_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ pub fn serde_as(args: TokenStream, input: TokenStream) -> TokenStream {
_ if cfg!(not(feature = "schemars_0_8")) => SchemaFieldConfig::Disabled,
Some(true) => SchemaFieldConfig::Unconditional,
Some(false) => SchemaFieldConfig::Disabled,
None => crate::utils::has_derive_jsonschema(input.clone()),
None => utils::has_derive_jsonschema(input.clone()),
};

// Convert any error message into a nice compiler error
Expand Down Expand Up @@ -769,9 +769,9 @@ fn serde_as_add_attr_to_field(
field.attrs.push(attr);

if let Some(cfg) = schemars_config.cfg_expr() {
let with_cfg = crate::utils::schemars_with_attr_if(
let with_cfg = utils::schemars_with_attr_if(
&field.attrs,
&["with", "serialize_with", "deserialize_with"],
&["with", "serialize_with", "deserialize_with", "schema_with"],
)?;
let attr_inner_tokens =
quote!(#serde_with_crate_path::Schema::<#type_original, #replacement_type>)
Expand All @@ -796,8 +796,10 @@ fn serde_as_add_attr_to_field(
field.attrs.push(attr);

if let Some(cfg) = schemars_config.cfg_expr() {
let with_cfg =
crate::utils::schemars_with_attr_if(&field.attrs, &["with", "deserialize_with"])?;
let with_cfg = utils::schemars_with_attr_if(
&field.attrs,
&["with", "deserialize_with", "schema_with"],
)?;
let attr_inner_tokens =
quote!(#serde_with_crate_path::Schema::<#type_original, #replacement_type>::deserialize)
.to_string();
Expand All @@ -818,8 +820,10 @@ fn serde_as_add_attr_to_field(
field.attrs.push(attr);

if let Some(cfg) = schemars_config.cfg_expr() {
let with_cfg =
crate::utils::schemars_with_attr_if(&field.attrs, &["with", "serialize_with"])?;
let with_cfg = utils::schemars_with_attr_if(
&field.attrs,
&["with", "serialize_with", "schema_with"],
)?;
let attr_inner_tokens =
quote!(#serde_with_crate_path::Schema::<#type_original, #replacement_type>::serialize)
.to_string();
Expand Down
Loading