diff --git a/serde_with/CHANGELOG.md b/serde_with/CHANGELOG.md index fe6e632a..58b6ba8f 100644 --- a/serde_with/CHANGELOG.md +++ b/serde_with/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +* Implement (De)Serialization for Pinned Smart Pointers by @Astralchroma (#733) + ## [3.7.0] - 2024-03-11 ### Added diff --git a/serde_with/src/de/impls.rs b/serde_with/src/de/impls.rs index 50838b30..6b83ca3b 100644 --- a/serde_with/src/de/impls.rs +++ b/serde_with/src/de/impls.rs @@ -110,6 +110,25 @@ pub(crate) mod macros { /////////////////////////////////////////////////////////////////////////////// // region: Simple Wrapper types (e.g., Box, Option) +#[allow(unused_macros)] +macro_rules! pinned_wrapper { + ($wrapper:ident) => { + impl<'de, T, U> DeserializeAs<'de, Pin<$wrapper>> for Pin<$wrapper> + where + U: DeserializeAs<'de, T>, + { + fn deserialize_as(deserializer: D) -> Result>, D::Error> + where + D: Deserializer<'de>, + { + Ok($wrapper::pin( + DeserializeAsWrap::::deserialize(deserializer)?.into_inner(), + )) + } + } + }; +} + #[cfg(feature = "alloc")] impl<'de, T, U> DeserializeAs<'de, Box> for Box where @@ -125,6 +144,9 @@ where } } +#[cfg(feature = "alloc")] +pinned_wrapper!(Box); + impl<'de, T, U> DeserializeAs<'de, Option> for Option where U: DeserializeAs<'de, T>, @@ -207,6 +229,9 @@ where } } +#[cfg(feature = "alloc")] +pinned_wrapper!(Rc); + #[cfg(feature = "alloc")] impl<'de, T, U> DeserializeAs<'de, RcWeak> for RcWeak where @@ -236,6 +261,9 @@ where } } +#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] +pinned_wrapper!(Arc); + #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] impl<'de, T, U> DeserializeAs<'de, ArcWeak> for ArcWeak where diff --git a/serde_with/src/lib.rs b/serde_with/src/lib.rs index b96b6839..50c3585e 100644 --- a/serde_with/src/lib.rs +++ b/serde_with/src/lib.rs @@ -390,6 +390,7 @@ pub(crate) mod prelude { marker::PhantomData, ops::Bound, option::Option, + pin::Pin, result::Result, str::FromStr, time::Duration, diff --git a/serde_with/src/ser/impls.rs b/serde_with/src/ser/impls.rs index dac8cfa9..e42b9139 100644 --- a/serde_with/src/ser/impls.rs +++ b/serde_with/src/ser/impls.rs @@ -13,6 +13,8 @@ use indexmap_2::{IndexMap as IndexMap2, IndexSet as IndexSet2}; #[cfg(feature = "alloc")] type BoxedSlice = Box<[T]>; type Slice = [T]; +type Ref<'a, T> = &'a T; +type RefMut<'a, T> = &'a mut T; pub(crate) mod macros { // The unused_imports lint has false-positives around macros @@ -84,6 +86,23 @@ pub(crate) mod macros { /////////////////////////////////////////////////////////////////////////////// // region: Simple Wrapper types (e.g., Box, Option) +#[allow(unused_macros)] +macro_rules! pinned_wrapper { + ($wrapper:ident $($lifetime:lifetime)?) => { + impl<$($lifetime,)? T, U> SerializeAs>> for Pin<$wrapper<$($lifetime,)? U>> + where + U: SerializeAs, + { + fn serialize_as(source: &Pin<$wrapper<$($lifetime,)? T>>, serializer: S) -> Result + where + S: Serializer, + { + SerializeAsWrap::::new(source).serialize(serializer) + } + } + }; +} + impl<'a, T, U> SerializeAs<&'a T> for &'a U where U: SerializeAs, @@ -112,6 +131,9 @@ where } } +pinned_wrapper!(Ref 'a); +pinned_wrapper!(RefMut 'a); + #[cfg(feature = "alloc")] impl SerializeAs> for Box where @@ -125,6 +147,9 @@ where } } +#[cfg(feature = "alloc")] +pinned_wrapper!(Box); + impl SerializeAs> for Option where U: SerializeAs, @@ -171,6 +196,9 @@ where } } +#[cfg(feature = "alloc")] +pinned_wrapper!(Rc); + #[cfg(feature = "alloc")] impl SerializeAs> for RcWeak where @@ -198,6 +226,9 @@ where } } +#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] +pinned_wrapper!(Arc); + #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] impl SerializeAs> for ArcWeak where diff --git a/serde_with/tests/serde_as/lib.rs b/serde_with/tests/serde_as/lib.rs index 1ca1a070..c728ceea 100644 --- a/serde_with/tests/serde_as/lib.rs +++ b/serde_with/tests/serde_as/lib.rs @@ -23,6 +23,7 @@ use alloc::{ use core::{ cell::{Cell, RefCell}, ops::Bound, + pin::Pin, }; use expect_test::expect; use serde::{Deserialize, Serialize}; @@ -44,12 +45,31 @@ fn test_basic_wrappers() { is_equal(SBox(Box::new(123)), expect![[r#""123""#]]); + // Deserialization in generally is not possible, only for unpin types + #[serde_as] + #[derive(Debug, Serialize, PartialEq)] + struct SPin<'a>(#[serde_as(as = "Pin<&DisplayFromStr>")] Pin<&'a u32>); + let tmp = 123; + check_serialization(SPin(Pin::new(&tmp)), expect![[r#""123""#]]); + + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct SPinBox(#[serde_as(as = "Pin>")] Pin>); + + is_equal(SPinBox(Box::pin(123)), expect![[r#""123""#]]); + #[serde_as] #[derive(Debug, Serialize, Deserialize, PartialEq)] struct SRc(#[serde_as(as = "Rc")] Rc); is_equal(SRc(Rc::new(123)), expect![[r#""123""#]]); + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct SPinRc(#[serde_as(as = "Pin>")] Pin>); + + is_equal(SPinRc(Rc::pin(123)), expect![[r#""123""#]]); + #[serde_as] #[derive(Debug, Serialize, Deserialize)] struct SRcWeak(#[serde_as(as = "RcWeak")] RcWeak); @@ -66,6 +86,12 @@ fn test_basic_wrappers() { is_equal(SArc(Arc::new(123)), expect![[r#""123""#]]); + #[serde_as] + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct SPinArc(#[serde_as(as = "Pin>")] Pin>); + + is_equal(SPinArc(Arc::pin(123)), expect![[r#""123""#]]); + #[serde_as] #[derive(Debug, Serialize, Deserialize)] struct SArcWeak(#[serde_as(as = "ArcWeak")] ArcWeak);