//! Modules that help with serializing and deserializing struct fields via the //! `#[serde(with ="path")]` attribute. use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// A helper for serializing and deserializing fields which are "smart pointers", types like /// [std::sync::Arc], [std::rc::Rc], and [Box]. pub mod smart_ptr { use super::*; use std::{ops::Deref, rc::Rc, sync::Arc}; /// Trait for general smart pointers. pub trait SmartPtr: Deref { /// Creates a new pointer which points to the given target. fn new(inner: Self::Target) -> Self; } macro_rules! impl_smart_ptr { ($ptr:ident) => { impl<T> SmartPtr for $ptr<T> { fn new(inner: Self::Target) -> Self { $ptr::new(inner) } } }; } impl_smart_ptr!(Arc); impl_smart_ptr!(Box); impl_smart_ptr!(Rc); pub fn serialize<P, T, S>(field: &P, ser: S) -> Result<S::Ok, S::Error> where P: SmartPtr<Target = T>, T: ?Sized + Serialize, S: Serializer, { field.deref().serialize(ser) } pub fn deserialize<'de, P, T, D>(de: D) -> Result<P, D::Error> where P: SmartPtr<Target = T>, T: ?Sized + Deserialize<'de>, D: Deserializer<'de>, { Ok(P::new(T::deserialize(de)?)) } } #[cfg(test)] mod smart_ptr_tests { use crate::{from_vec, to_vec}; use paste::paste; use serde::{Deserialize, Serialize}; use std::{rc::Rc, sync::Arc}; use super::smart_ptr::{self, SmartPtr}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct Test<P: SmartPtr<Target = String>> { #[serde(with = "smart_ptr")] field: P, } impl<P: SmartPtr<Target = String>> Test<P> { fn new(expected: &str) -> Self { Test { field: P::new(expected.to_string()), } } } macro_rules! check_ptr { ($ptr:ty) => { paste! { #[test] fn [<"check_" $ptr:lower>]() { let expected = Test::new("expected"); let actual: Test<$ptr<String>> = from_vec(&to_vec(&expected).unwrap()).unwrap(); assert_eq!(expected, actual); } } }; } check_ptr!(Arc); check_ptr!(Box); check_ptr!(Rc); }