Skip to content

Commit

Permalink
Document new serde_as behavior
Browse files Browse the repository at this point in the history
Document when `serde_as` will add `#[serde(default)]` on a field.
  • Loading branch information
jonasbb committed Jun 6, 2022
1 parent e7f2f5e commit 5d84054
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
17 changes: 17 additions & 0 deletions serde_with/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Changed

* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.

The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.

The `Option` field and transformation are detected by directly matching on the type name.
These variants are detected as `Option`.
* `Option`
* `std::option::Option`, with or without leading `::`
* `core::option::Option`, with or without leading `::`

If an existing `default` attribute is detected, the attribute is not applied again.
This behavior can be supressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.

## [1.14.0] - 2022-05-29

### Added
Expand Down
19 changes: 18 additions & 1 deletion serde_with_macros/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Changed

* Make `#[serde_as]` behave more intuitive on `Option<T>` fields.

The `#[serde_as]` macro now detects if a `#[serde_as(as = "Option<S>")]` is used on a field of type `Option<T>` and applies `#[serde(default)]` to the field.
This restores the ability to deserialize with missing fields and fixes a common annoyance (#183, #185, #311, #417).
This is a breaking change, since now deserialization will pass where it did not before and this might be undesired.

The `Option` field and transformation are detected by directly matching on the type name.
These variants are detected as `Option`.
* `Option`
* `std::option::Option`, with or without leading `::`
* `core::option::Option`, with or without leading `::`

If an existing `default` attribute is detected, the attribute is not applied again.
This behavior can be supressed by using `#[serde_as(no_default)]` or `#[serde_as(as = "Option<S>", no_default)]`.

### Fixed

* Make the documentation clearer by stating that the `#[serde_as]` and `#[skip_serializing_none]` attributes must always be places before `#[derive]`.
* Make the documentation clearer by stating that the `#[serde_as]` and `#[skip_serializing_none]` attributes must always be placed before `#[derive]`.

## [1.5.2] - 2022-04-07

Expand Down
25 changes: 25 additions & 0 deletions serde_with_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,9 @@ fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool {
/// struct Foo {
/// #[serde_as(as = "Vec<_>")]
/// bar: Vec<u32>,
///
/// #[serde_as(as = "Option<DisplayFromStr>")]
/// baz: Option<u32>,
/// }
/// ```
///
Expand All @@ -489,6 +492,23 @@ fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool {
/// 4. It searches `#[serde_as(as = ...)]` if there is a type named `BorrowCow` under any path.
/// If `BorrowCow` is found, the attribute `#[serde(borrow)]` is added to the field.
/// If `#[serde(borrow)]` or `#[serde(borrow = "...")]` is already present, this step will be skipped.
/// 5. Restore the ability of accepting missing fields if both the field and the transformation are `Option`.
///
/// An `Option` is detected by an exact text match.
/// Renaming an import or type aliases can cause confusion here.
/// The following variants are supported.
/// * `Option`
/// * `std::option::Option`, with or without leading `::`
/// * `core::option::Option`, with or without leading `::`
///
/// If the field is of type `Option<T>` and the attribute `#[serde_as(as = "Option<S>")]` (also `deserialize_as`; for any `T`/`S`) then `#[serde(default)]` is applied to the field.
/// This restores the ability of accepting missing fields, which otherwise often leads to confusing [serde_with#185](https://github.com/jonasbb/serde_with/issues/185).
/// `#[serde(default)]` is not applied, if it already exists.
/// It only triggers if both field and transformation are `Option`s.
/// For example, using `#[serde_as(as = "NoneAsEmptyString")]` on `Option<String>` will not see any change.
///
/// If the automatically applied attribute is undesired, the behavior can be supressed by adding `#[serde_as(no_default)]`.
/// This can be combined like `#[serde_as(as = "Option<S>", no_default)]`.
///
/// After all these steps, the code snippet will have transformed into roughly this.
///
Expand All @@ -498,6 +518,11 @@ fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool {
/// #[serde_as(as = "Vec<_>")]
/// #[serde(with = "::serde_with::As::<Vec<::serde_with::Same>>")]
/// bar: Vec<u32>,
///
/// #[serde_as(as = "Option<DisplayFromStr>")]
/// #[serde(default)]
/// #[serde(with = "::serde_with::As::<Option<DisplayFromStr>>")]
/// baz: Option<u32>,
/// }
/// ```
///
Expand Down

0 comments on commit 5d84054

Please sign in to comment.