Skip to content

Commit

Permalink
Implement (De)Serialization for Pinned Smart Pointers (#733)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasbb committed Apr 24, 2024
2 parents 9989d8e + 04de4ce commit 167e865
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 0 deletions.
2 changes: 2 additions & 0 deletions serde_with/CHANGELOG.md
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions serde_with/src/de/impls.rs
Expand Up @@ -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<T>>> for Pin<$wrapper<U>>
where
U: DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<Pin<$wrapper<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok($wrapper::pin(
DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
))
}
}
};
}

#[cfg(feature = "alloc")]
impl<'de, T, U> DeserializeAs<'de, Box<T>> for Box<U>
where
Expand All @@ -125,6 +144,9 @@ where
}
}

#[cfg(feature = "alloc")]
pinned_wrapper!(Box);

impl<'de, T, U> DeserializeAs<'de, Option<T>> for Option<U>
where
U: DeserializeAs<'de, T>,
Expand Down Expand Up @@ -207,6 +229,9 @@ where
}
}

#[cfg(feature = "alloc")]
pinned_wrapper!(Rc);

#[cfg(feature = "alloc")]
impl<'de, T, U> DeserializeAs<'de, RcWeak<T>> for RcWeak<U>
where
Expand Down Expand Up @@ -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<T>> for ArcWeak<U>
where
Expand Down
1 change: 1 addition & 0 deletions serde_with/src/lib.rs
Expand Up @@ -390,6 +390,7 @@ pub(crate) mod prelude {
marker::PhantomData,
ops::Bound,
option::Option,
pin::Pin,
result::Result,
str::FromStr,
time::Duration,
Expand Down
31 changes: 31 additions & 0 deletions serde_with/src/ser/impls.rs
Expand Up @@ -13,6 +13,8 @@ use indexmap_2::{IndexMap as IndexMap2, IndexSet as IndexSet2};
#[cfg(feature = "alloc")]
type BoxedSlice<T> = Box<[T]>;
type Slice<T> = [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
Expand Down Expand Up @@ -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<Pin<$wrapper<$($lifetime,)? T>>> for Pin<$wrapper<$($lifetime,)? U>>
where
U: SerializeAs<T>,
{
fn serialize_as<S>(source: &Pin<$wrapper<$($lifetime,)? T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
SerializeAsWrap::<T, U>::new(source).serialize(serializer)
}
}
};
}

impl<'a, T, U> SerializeAs<&'a T> for &'a U
where
U: SerializeAs<T>,
Expand Down Expand Up @@ -112,6 +131,9 @@ where
}
}

pinned_wrapper!(Ref 'a);
pinned_wrapper!(RefMut 'a);

#[cfg(feature = "alloc")]
impl<T, U> SerializeAs<Box<T>> for Box<U>
where
Expand All @@ -125,6 +147,9 @@ where
}
}

#[cfg(feature = "alloc")]
pinned_wrapper!(Box);

impl<T, U> SerializeAs<Option<T>> for Option<U>
where
U: SerializeAs<T>,
Expand Down Expand Up @@ -171,6 +196,9 @@ where
}
}

#[cfg(feature = "alloc")]
pinned_wrapper!(Rc);

#[cfg(feature = "alloc")]
impl<T, U> SerializeAs<RcWeak<T>> for RcWeak<U>
where
Expand Down Expand Up @@ -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<T, U> SerializeAs<ArcWeak<T>> for ArcWeak<U>
where
Expand Down
26 changes: 26 additions & 0 deletions serde_with/tests/serde_as/lib.rs
Expand Up @@ -23,6 +23,7 @@ use alloc::{
use core::{
cell::{Cell, RefCell},
ops::Bound,
pin::Pin,
};
use expect_test::expect;
use serde::{Deserialize, Serialize};
Expand All @@ -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<Box<DisplayFromStr>>")] Pin<Box<u32>>);

is_equal(SPinBox(Box::pin(123)), expect![[r#""123""#]]);

#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SRc(#[serde_as(as = "Rc<DisplayFromStr>")] Rc<u32>);

is_equal(SRc(Rc::new(123)), expect![[r#""123""#]]);

#[serde_as]
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SPinRc(#[serde_as(as = "Pin<Rc<DisplayFromStr>>")] Pin<Rc<u32>>);

is_equal(SPinRc(Rc::pin(123)), expect![[r#""123""#]]);

#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SRcWeak(#[serde_as(as = "RcWeak<DisplayFromStr>")] RcWeak<u32>);
Expand All @@ -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<Arc<DisplayFromStr>>")] Pin<Arc<u32>>);

is_equal(SPinArc(Arc::pin(123)), expect![[r#""123""#]]);

#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
struct SArcWeak(#[serde_as(as = "ArcWeak<DisplayFromStr>")] ArcWeak<u32>);
Expand Down

0 comments on commit 167e865

Please sign in to comment.