Repository: jonasbb/serde_with
Pull request #832 (2025-04-29 11:05:27)

makes unwrap_or_skip compatible with references (zero-copy)
`rust::unwrap_or_skip` was incompatible with references (zero-copy). See examples of this incompatibility in the new tests.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/jonasbb/serde_with/pull/832?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Bushart) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 68.51%. Comparing base [(`1b39567`)](https://app.codecov.io/gh/jonasbb/serde_with/commit/1b395677fc9565c3191c9e3668f5ed3104560562?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Bushart) to head [(`34ed0ef`)](https://app.codecov.io/gh/jonasbb/serde_with/commit/34ed0ef889a781c6a36223187b9e88d3d5bd1d76?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Bushart).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #832      +/-   ##
==========================================
- Coverage   70.58%   68.51%   -2.08%     
==========================================
  Files          34       34              
  Lines        9863     9273     -590     
==========================================
- Hits         6962     6353     -609     
- Misses       2901     2920      +19     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/jonasbb/serde_with/pull/832?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Bushart).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jonas+Bushart).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/serde_with/CHANGELOG.md b/serde_with/CHANGELOG.md
index 4341304..008539e 100644
--- a/serde_with/CHANGELOG.md
+++ b/serde_with/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
 
 ## [Unreleased]
 
+### Changed
+
+* Generalize `serde_with::rust::unwrap_or_skip` to support deserializing references by @beroal (#832)
+
 ## [3.12.0] - 2024-12-25
 
 ### Added
diff --git a/serde_with/src/rust.rs b/serde_with/src/rust.rs
index bae825e..526a8a7 100644
--- a/serde_with/src/rust.rs
+++ b/serde_with/src/rust.rs
@@ -149,7 +149,7 @@ pub mod unwrap_or_skip {
     pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
     where
         D: Deserializer<'de>,
-        T: DeserializeOwned,
+        T: Deserialize<'de>,
     {
         T::deserialize(deserializer).map(Some)
     }


Test patch:
diff --git a/serde_with/tests/rust.rs b/serde_with/tests/rust.rs
index 0cc1eba..4c74633 100644
--- a/serde_with/tests/rust.rs
+++ b/serde_with/tests/rust.rs
@@ -378,3 +378,114 @@ fn duplicate_value_last_wins_btreeset() {
     assert_eq!(2, entries[1].0);
     assert!(!entries[1].1);
 }
+
+#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
+struct UnwrapOrSkipRef<'a> {
+    #[serde(
+        default,
+        skip_serializing_if = "Option::is_none",
+        with = "::serde_with::rust::unwrap_or_skip"
+    )]
+    option_field: Option<&'a str>,
+
+    field: &'a str,
+}
+
+#[test]
+fn unwrap_or_skip_ref_some() {
+    let s0 = String::from("g1_&");
+    let s1 = String::from("3&t");
+    let value = UnwrapOrSkipRef {
+        option_field: Some(s0.as_ref()),
+        field: s1.as_ref(),
+    };
+    let expected = expect![[r#"
+        {
+          "option_field": "g1_&",
+          "field": "3&t"
+        }"#]];
+
+    // I can't make the following check abstract over [`UnwrapOrSkipRef`]
+    // because of incompatible lifetimes.
+    let serialized = serde_json::to_string_pretty(&value).unwrap();
+    expected.assert_eq(&serialized);
+    assert_eq!(
+        value,
+        serde_json::from_str::<UnwrapOrSkipRef<'_>>(&serialized).unwrap(),
+        "Deserialization differs from expected value."
+    );
+}
+
+#[test]
+fn unwrap_or_skip_ref_none() {
+    let s1 = String::from("3&t");
+    let value = UnwrapOrSkipRef {
+        option_field: None,
+        field: s1.as_ref(),
+    };
+    let expected = expect![[r#"
+        {
+          "field": "3&t"
+        }"#]];
+
+    let serialized = serde_json::to_string_pretty(&value).unwrap();
+    expected.assert_eq(&serialized);
+    assert_eq!(
+        value,
+        serde_json::from_str::<UnwrapOrSkipRef<'_>>(&serialized).unwrap(),
+        "Deserialization differs from expected value."
+    );
+}
+
+#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
+struct UnwrapOrSkip {
+    #[serde(
+        default,
+        skip_serializing_if = "Option::is_none",
+        with = "::serde_with::rust::unwrap_or_skip"
+    )]
+    option_field: Option<String>,
+
+    field: String,
+}
+
+#[test]
+fn unwrap_or_skip_some() {
+    let value = UnwrapOrSkip {
+        option_field: Some(String::from("g1_&")),
+        field: String::from("3&t"),
+    };
+    let expected = expect![[r#"
+        {
+          "option_field": "g1_&",
+          "field": "3&t"
+        }"#]];
+
+    let serialized = serde_json::to_string_pretty(&value).unwrap();
+    expected.assert_eq(&serialized);
+    assert_eq!(
+        value,
+        serde_json::from_str::<UnwrapOrSkip>(&serialized).unwrap(),
+        "Deserialization differs from expected value."
+    );
+}
+
+#[test]
+fn unwrap_or_skip_none() {
+    let value = UnwrapOrSkip {
+        option_field: None,
+        field: String::from("3&t"),
+    };
+    let expected = expect![[r#"
+        {
+          "field": "3&t"
+        }"#]];
+
+    let serialized = serde_json::to_string_pretty(&value).unwrap();
+    expected.assert_eq(&serialized);
+    assert_eq!(
+        value,
+        serde_json::from_str::<UnwrapOrSkip>(&serialized).unwrap(),
+        "Deserialization differs from expected value."
+    );
+}