//! Analog of [serde_with](https://docs.rs/serde_with) for [borsh](https://docs.rs/borsh) use std::{ fmt::{self, Display}, io::{self, Read}, marker::PhantomData, rc::Rc, sync::Arc, }; use defuse_io_utils::ReadExt; use impl_tools::autoimpl; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; #[cfg(feature = "chrono")] mod chrono; #[cfg(feature = "chrono")] pub use self::chrono::*; pub trait BorshSerializeAs { fn serialize_as(source: &T, writer: &mut W) -> io::Result<()> where W: io::Write; } pub trait BorshDeserializeAs { fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read; } pub struct As(PhantomData); impl As { #[inline] pub fn serialize(obj: &U, writer: &mut W) -> io::Result<()> where T: BorshSerializeAs, W: io::Write, U: ?Sized, { T::serialize_as(obj, writer) } #[inline] pub fn deserialize(reader: &mut R) -> io::Result where T: BorshDeserializeAs, R: io::Read, { T::deserialize_as(reader) } } /// Analog for [`serde_with::Same`](https://docs.rs/serde_with/latest/serde_with/struct.Same.html) #[derive(Debug, Eq, PartialEq)] pub struct Same; impl BorshSerializeAs for Same where T: BorshSerialize, { #[inline] fn serialize_as(source: &T, writer: &mut W) -> io::Result<()> where W: io::Write, { source.serialize(writer) } } impl BorshDeserializeAs for Same where T: BorshDeserialize, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read, { T::deserialize_reader(reader) } } #[autoimpl(Deref using self.value)] #[autoimpl(DerefMut using self.value)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AsWrap { value: T, _marker: PhantomData, } impl AsWrap { #[must_use] #[inline] pub const fn new(value: T) -> Self { Self { value, _marker: PhantomData, } } /// Return the inner value of type `T`. #[inline] pub fn into_inner(self) -> T { self.value } } impl From for AsWrap { #[inline] fn from(value: T) -> Self { Self::new(value) } } pub fn to_vec_as(source: &T) -> io::Result> where As: BorshSerializeAs + ?Sized, { borsh::to_vec(&AsWrap::<&T, &As>::new(source)) } impl BorshDeserialize for AsWrap where As: BorshDeserializeAs + ?Sized, { #[inline] fn deserialize_reader(reader: &mut R) -> io::Result { As::deserialize_as(reader).map(Self::new) } } impl BorshSerialize for AsWrap where As: BorshSerializeAs + ?Sized, { #[inline] fn serialize(&self, writer: &mut W) -> io::Result<()> { As::serialize_as(&self.value, writer) } } impl fmt::Debug for AsWrap where T: fmt::Debug, As: ?Sized, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.value, f) } } impl fmt::Display for AsWrap where T: fmt::Display, As: ?Sized, { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.value, f) } } impl BorshSerializeAs<&T> for &As where T: ?Sized, As: BorshSerializeAs + ?Sized, { #[inline] fn serialize_as(source: &&T, writer: &mut W) -> io::Result<()> where W: io::Write, { As::serialize_as(source, writer) } } impl BorshSerializeAs<&mut T> for &mut As where T: ?Sized, As: BorshSerializeAs + ?Sized, { #[inline] fn serialize_as(source: &&mut T, writer: &mut W) -> io::Result<()> where W: io::Write, { As::serialize_as(source, writer) } } impl BorshSerializeAs> for Option where As: BorshSerializeAs, { #[inline] fn serialize_as(source: &Option, writer: &mut W) -> io::Result<()> where W: io::Write, { source .as_ref() .map(AsWrap::<&T, &As>::new) .serialize(writer) } } impl BorshDeserializeAs> for Option where As: BorshDeserializeAs, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result> where R: io::Read, { Ok(Option::>::deserialize_reader(reader)?.map(AsWrap::into_inner)) } } impl BorshSerializeAs> for Box where As: BorshSerializeAs + ?Sized, { #[inline] fn serialize_as(source: &Box, writer: &mut W) -> io::Result<()> where W: io::Write, { AsWrap::<&T, &As>::new(source).serialize(writer) } } impl BorshDeserializeAs> for Box where As: BorshDeserializeAs + ?Sized, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result> where R: io::Read, { AsWrap::::deserialize_reader(reader) .map(AsWrap::into_inner) .map(Box::new) } } impl BorshSerializeAs> for Rc where As: BorshSerializeAs + ?Sized, { #[inline] fn serialize_as(source: &Rc, writer: &mut W) -> io::Result<()> where W: io::Write, { AsWrap::<&T, &As>::new(source).serialize(writer) } } impl BorshDeserializeAs> for Rc where As: BorshDeserializeAs + ?Sized, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result> where R: io::Read, { AsWrap::::deserialize_reader(reader) .map(AsWrap::into_inner) .map(Rc::new) } } impl BorshSerializeAs> for Arc where As: BorshSerializeAs + ?Sized, { #[inline] fn serialize_as(source: &Arc, writer: &mut W) -> io::Result<()> where W: io::Write, { AsWrap::<&T, &As>::new(source).serialize(writer) } } impl BorshDeserializeAs> for Arc where As: BorshDeserializeAs + ?Sized, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result> where R: io::Read, { AsWrap::::deserialize_reader(reader) .map(AsWrap::into_inner) .map(Arc::new) } } impl BorshSerializeAs<[T]> for [As] where As: BorshSerializeAs, { #[inline] fn serialize_as(source: &[T], writer: &mut W) -> io::Result<()> where W: io::Write, { source.iter().try_for_each(|v| As::serialize_as(v, writer)) } } impl BorshSerializeAs<[T; N]> for [As; N] where As: BorshSerializeAs, { #[inline] fn serialize_as(source: &[T; N], writer: &mut W) -> io::Result<()> where W: io::Write, { <&[As]>::serialize_as(&source.as_slice(), writer) } } impl BorshDeserializeAs<[T; N]> for [As; N] where As: BorshDeserializeAs, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result<[T; N]> where R: io::Read, { // TODO: replace with [`core::array::try_from_fn`](https://github.com/rust-lang/rust/issues/89379) when stabilized array_util::try_from_fn(|_i| As::deserialize_as(reader)) } } macro_rules! impl_borsh_serde_as_for_tuple { ($($n:tt:$t:ident as $a:ident),+) => { impl<$($t, $a),+> BorshSerializeAs<($($t,)+)> for ($($a,)+) where $( $a: BorshSerializeAs<$t>, )+ { #[inline] fn serialize_as(source: &($($t,)+), writer: &mut W) -> io::Result<()> where W: io::Write, { $( $a::serialize_as(&source.$n, writer)?; )+ Ok(()) } } impl<$($t, $a),+> BorshDeserializeAs<($($t,)+)> for ($($a,)+) where $( $a: BorshDeserializeAs<$t>, )+ { #[inline] fn deserialize_as(reader: &mut R) -> io::Result<($($t,)+)> where R: io::Read, { Ok(($( $a::deserialize_as(reader)?, )+)) } } }; } impl_borsh_serde_as_for_tuple!(0:T0 as As0); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7,8:T8 as As8); impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4,5:T5 as As5,6:T6 as As6,7:T7 as As7,8:T8 as As8,9:T9 as As9); pub struct FromInto(PhantomData); impl BorshSerializeAs for FromInto where T: Into + Clone, U: BorshSerialize, { #[inline] fn serialize_as(source: &T, writer: &mut W) -> io::Result<()> where W: io::Write, { source.clone().into().serialize(writer) } } impl BorshDeserializeAs for FromInto where U: BorshDeserialize + Into, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read, { U::deserialize_reader(reader).map(Into::into) } } pub struct FromIntoRef(PhantomData); impl BorshSerializeAs for FromIntoRef where for<'a> &'a T: Into, U: BorshSerialize, { #[inline] fn serialize_as(source: &T, writer: &mut W) -> io::Result<()> where W: io::Write, { source.into().serialize(writer) } } impl BorshDeserializeAs for FromIntoRef where U: BorshDeserialize + Into, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read, { U::deserialize_reader(reader).map(Into::into) } } pub struct TryFromInto(PhantomData); impl BorshSerializeAs for TryFromInto where T: TryInto + Clone, >::Error: Display, U: BorshSerialize, { #[inline] fn serialize_as(source: &T, writer: &mut W) -> io::Result<()> where W: io::Write, { source .clone() .try_into() .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))? .serialize(writer) } } impl BorshDeserializeAs for TryFromInto where U: BorshDeserialize + TryInto, >::Error: Display, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read, { U::deserialize_reader(reader).and_then(|v| { v.try_into() .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string())) }) } } pub struct Or(PhantomData, PhantomData); impl BorshDeserializeAs for Or where As1: BorshDeserializeAs + ?Sized, As2: BorshDeserializeAs + ?Sized, { #[inline] fn deserialize_as(reader: &mut R) -> io::Result where R: io::Read, { let mut buf = Vec::new(); As1::deserialize_as(&mut reader.tee(&mut buf)) .or_else(|_| As2::deserialize_as(&mut buf.chain(reader))) } } #[cfg(test)] mod tests;