Skip to main content

defuse_borsh_utils/
lib.rs

1//! Analog of [serde_with](https://docs.rs/serde_with) for [borsh](https://docs.rs/borsh)
2
3use std::{
4    fmt::{self, Display},
5    io::{self, Read},
6    marker::PhantomData,
7    rc::Rc,
8    sync::Arc,
9};
10
11use borsh::{self, BorshDeserialize, BorshSerialize};
12use defuse_io_utils::ReadExt;
13use impl_tools::autoimpl;
14
15#[cfg(feature = "schema")]
16mod schema;
17#[cfg(feature = "schema")]
18pub use self::schema::*;
19
20mod duration;
21pub use self::duration::*;
22
23pub trait BorshSerializeAs<T: ?Sized> {
24    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
25    where
26        W: io::Write;
27}
28
29pub trait BorshDeserializeAs<T> {
30    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
31    where
32        R: io::Read;
33}
34
35pub struct As<T: ?Sized>(PhantomData<T>);
36
37impl<T: ?Sized> As<T> {
38    #[inline]
39    pub fn serialize<U, W>(obj: &U, writer: &mut W) -> io::Result<()>
40    where
41        T: BorshSerializeAs<U>,
42        W: io::Write,
43        U: ?Sized,
44    {
45        T::serialize_as(obj, writer)
46    }
47
48    #[inline]
49    pub fn deserialize<R, U>(reader: &mut R) -> io::Result<U>
50    where
51        T: BorshDeserializeAs<U>,
52        R: io::Read,
53    {
54        T::deserialize_as(reader)
55    }
56}
57
58/// Analog for [`serde_with::Same`](https://docs.rs/serde_with/latest/serde_with/struct.Same.html)
59#[derive(Debug, Eq, PartialEq)]
60pub struct Same;
61
62impl<T> BorshSerializeAs<T> for Same
63where
64    T: BorshSerialize,
65{
66    #[inline]
67    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
68    where
69        W: io::Write,
70    {
71        source.serialize(writer)
72    }
73}
74
75impl<T> BorshDeserializeAs<T> for Same
76where
77    T: BorshDeserialize,
78{
79    #[inline]
80    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
81    where
82        R: io::Read,
83    {
84        T::deserialize_reader(reader)
85    }
86}
87
88/// An adaptor to convert from [`BorshSerializeAs`] and [`BorshDeserializeAs`]
89/// to the corresponding [`borsh`] traits.
90#[autoimpl(Deref using self.value)]
91#[autoimpl(DerefMut using self.value)]
92#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub struct AsWrap<T, As: ?Sized> {
94    value: T,
95    _marker: PhantomData<As>,
96}
97
98impl<T, As: ?Sized> AsWrap<T, As> {
99    #[must_use]
100    #[inline]
101    pub const fn new(value: T) -> Self {
102        Self {
103            value,
104            _marker: PhantomData,
105        }
106    }
107
108    /// Return the inner value of type `T`.
109    #[inline]
110    pub fn into_inner(self) -> T {
111        self.value
112    }
113}
114
115impl<T, As: ?Sized> From<T> for AsWrap<T, As> {
116    #[inline]
117    fn from(value: T) -> Self {
118        Self::new(value)
119    }
120}
121
122pub fn to_vec_as<T, As>(source: &T) -> io::Result<Vec<u8>>
123where
124    As: BorshSerializeAs<T> + ?Sized,
125{
126    borsh::to_vec(&AsWrap::<&T, &As>::new(source))
127}
128
129impl<T, As> BorshDeserialize for AsWrap<T, As>
130where
131    As: BorshDeserializeAs<T> + ?Sized,
132{
133    #[inline]
134    fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
135        As::deserialize_as(reader).map(Self::new)
136    }
137}
138
139impl<T, As> BorshSerialize for AsWrap<T, As>
140where
141    As: BorshSerializeAs<T> + ?Sized,
142{
143    #[inline]
144    fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
145        As::serialize_as(&self.value, writer)
146    }
147}
148
149#[cfg(feature = "schema")]
150const _: () = {
151    use borsh::schema::{Declaration, Definition};
152    use std::collections::BTreeMap;
153
154    impl<T, As> borsh::BorshSchema for AsWrap<T, As>
155    where
156        T: borsh::BorshSchema,
157        As: ?Sized,
158    {
159        fn declaration() -> Declaration {
160            T::declaration()
161        }
162
163        fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
164            T::add_definitions_recursively(definitions);
165        }
166    }
167};
168
169impl<T, As> fmt::Debug for AsWrap<T, As>
170where
171    T: fmt::Debug,
172    As: ?Sized,
173{
174    #[inline]
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        fmt::Debug::fmt(&self.value, f)
177    }
178}
179
180impl<T, As> fmt::Display for AsWrap<T, As>
181where
182    T: fmt::Display,
183    As: ?Sized,
184{
185    #[inline]
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        fmt::Display::fmt(&self.value, f)
188    }
189}
190
191impl<T, As> BorshSerializeAs<&T> for &As
192where
193    T: ?Sized,
194    As: BorshSerializeAs<T> + ?Sized,
195{
196    #[inline]
197    fn serialize_as<W>(source: &&T, writer: &mut W) -> io::Result<()>
198    where
199        W: io::Write,
200    {
201        As::serialize_as(source, writer)
202    }
203}
204
205impl<T, As> BorshSerializeAs<&mut T> for &mut As
206where
207    T: ?Sized,
208    As: BorshSerializeAs<T> + ?Sized,
209{
210    #[inline]
211    fn serialize_as<W>(source: &&mut T, writer: &mut W) -> io::Result<()>
212    where
213        W: io::Write,
214    {
215        As::serialize_as(source, writer)
216    }
217}
218
219impl<T, As> BorshSerializeAs<Option<T>> for Option<As>
220where
221    As: BorshSerializeAs<T>,
222{
223    #[inline]
224    fn serialize_as<W>(source: &Option<T>, writer: &mut W) -> io::Result<()>
225    where
226        W: io::Write,
227    {
228        source
229            .as_ref()
230            .map(AsWrap::<&T, &As>::new)
231            .serialize(writer)
232    }
233}
234
235impl<T, As> BorshDeserializeAs<Option<T>> for Option<As>
236where
237    As: BorshDeserializeAs<T>,
238{
239    #[inline]
240    fn deserialize_as<R>(reader: &mut R) -> io::Result<Option<T>>
241    where
242        R: io::Read,
243    {
244        Ok(Option::<AsWrap<T, As>>::deserialize_reader(reader)?.map(AsWrap::into_inner))
245    }
246}
247
248impl<T, As> BorshSerializeAs<Box<T>> for Box<As>
249where
250    As: BorshSerializeAs<T> + ?Sized,
251{
252    #[inline]
253    fn serialize_as<W>(source: &Box<T>, writer: &mut W) -> io::Result<()>
254    where
255        W: io::Write,
256    {
257        AsWrap::<&T, &As>::new(source).serialize(writer)
258    }
259}
260
261impl<T, As> BorshDeserializeAs<Box<T>> for Box<As>
262where
263    As: BorshDeserializeAs<T> + ?Sized,
264{
265    #[inline]
266    fn deserialize_as<R>(reader: &mut R) -> io::Result<Box<T>>
267    where
268        R: io::Read,
269    {
270        AsWrap::<T, As>::deserialize_reader(reader)
271            .map(AsWrap::into_inner)
272            .map(Box::new)
273    }
274}
275
276impl<T, As> BorshSerializeAs<Rc<T>> for Rc<As>
277where
278    As: BorshSerializeAs<T> + ?Sized,
279{
280    #[inline]
281    fn serialize_as<W>(source: &Rc<T>, writer: &mut W) -> io::Result<()>
282    where
283        W: io::Write,
284    {
285        AsWrap::<&T, &As>::new(source).serialize(writer)
286    }
287}
288
289impl<T, As> BorshDeserializeAs<Rc<T>> for Rc<As>
290where
291    As: BorshDeserializeAs<T> + ?Sized,
292{
293    #[inline]
294    fn deserialize_as<R>(reader: &mut R) -> io::Result<Rc<T>>
295    where
296        R: io::Read,
297    {
298        AsWrap::<T, As>::deserialize_reader(reader)
299            .map(AsWrap::into_inner)
300            .map(Rc::new)
301    }
302}
303
304impl<T, As> BorshSerializeAs<Arc<T>> for Arc<As>
305where
306    As: BorshSerializeAs<T> + ?Sized,
307{
308    #[inline]
309    fn serialize_as<W>(source: &Arc<T>, writer: &mut W) -> io::Result<()>
310    where
311        W: io::Write,
312    {
313        AsWrap::<&T, &As>::new(source).serialize(writer)
314    }
315}
316
317impl<T, As> BorshDeserializeAs<Arc<T>> for Arc<As>
318where
319    As: BorshDeserializeAs<T> + ?Sized,
320{
321    #[inline]
322    fn deserialize_as<R>(reader: &mut R) -> io::Result<Arc<T>>
323    where
324        R: io::Read,
325    {
326        AsWrap::<T, As>::deserialize_reader(reader)
327            .map(AsWrap::into_inner)
328            .map(Arc::new)
329    }
330}
331
332impl<T, As> BorshSerializeAs<[T]> for [As]
333where
334    As: BorshSerializeAs<T>,
335{
336    #[inline]
337    fn serialize_as<W>(source: &[T], writer: &mut W) -> io::Result<()>
338    where
339        W: io::Write,
340    {
341        source.iter().try_for_each(|v| As::serialize_as(v, writer))
342    }
343}
344
345impl<T, As, const N: usize> BorshSerializeAs<[T; N]> for [As; N]
346where
347    As: BorshSerializeAs<T>,
348{
349    #[inline]
350    fn serialize_as<W>(source: &[T; N], writer: &mut W) -> io::Result<()>
351    where
352        W: io::Write,
353    {
354        <&[As]>::serialize_as(&source.as_slice(), writer)
355    }
356}
357
358impl<T, As, const N: usize> BorshDeserializeAs<[T; N]> for [As; N]
359where
360    As: BorshDeserializeAs<T>,
361{
362    #[inline]
363    fn deserialize_as<R>(reader: &mut R) -> io::Result<[T; N]>
364    where
365        R: io::Read,
366    {
367        // TODO: replace with [`core::array::try_from_fn`](https://github.com/rust-lang/rust/issues/89379) when stabilized
368        array_util::try_from_fn(|_i| As::deserialize_as(reader))
369    }
370}
371
372macro_rules! impl_borsh_serde_as_for_tuple {
373    ($($n:tt:$t:ident as $a:ident),+) => {
374        impl<$($t, $a),+> BorshSerializeAs<($($t,)+)> for ($($a,)+)
375        where $(
376            $a: BorshSerializeAs<$t>,
377        )+
378        {
379            #[inline]
380            fn serialize_as<W>(source: &($($t,)+), writer: &mut W) -> io::Result<()>
381            where
382                W: io::Write,
383            {
384                $(
385                    $a::serialize_as(&source.$n, writer)?;
386                )+
387                Ok(())
388            }
389        }
390
391        impl<$($t, $a),+> BorshDeserializeAs<($($t,)+)> for ($($a,)+)
392        where $(
393            $a: BorshDeserializeAs<$t>,
394        )+
395        {
396            #[inline]
397            fn deserialize_as<R>(reader: &mut R) -> io::Result<($($t,)+)>
398            where
399                R: io::Read,
400            {
401                Ok(($(
402                    $a::deserialize_as(reader)?,
403                )+))
404            }
405        }
406    };
407}
408impl_borsh_serde_as_for_tuple!(0:T0 as As0);
409impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1);
410impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2);
411impl_borsh_serde_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3);
412impl_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);
413impl_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);
414impl_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);
415impl_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);
416impl_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);
417impl_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);
418
419pub struct FromInto<T: ?Sized>(PhantomData<T>);
420
421impl<T, U> BorshSerializeAs<T> for FromInto<U>
422where
423    T: Into<U> + Clone,
424    U: BorshSerialize,
425{
426    #[inline]
427    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
428    where
429        W: io::Write,
430    {
431        source.clone().into().serialize(writer)
432    }
433}
434
435impl<T, U> BorshDeserializeAs<T> for FromInto<U>
436where
437    U: BorshDeserialize + Into<T>,
438{
439    #[inline]
440    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
441    where
442        R: io::Read,
443    {
444        U::deserialize_reader(reader).map(Into::into)
445    }
446}
447
448pub struct FromIntoRef<T: ?Sized>(PhantomData<T>);
449
450impl<T, U> BorshSerializeAs<T> for FromIntoRef<U>
451where
452    for<'a> &'a T: Into<U>,
453    U: BorshSerialize,
454{
455    #[inline]
456    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
457    where
458        W: io::Write,
459    {
460        source.into().serialize(writer)
461    }
462}
463
464impl<T, U> BorshDeserializeAs<T> for FromIntoRef<U>
465where
466    U: BorshDeserialize + Into<T>,
467{
468    #[inline]
469    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
470    where
471        R: io::Read,
472    {
473        U::deserialize_reader(reader).map(Into::into)
474    }
475}
476
477pub struct TryFromInto<T: ?Sized>(PhantomData<T>);
478
479impl<T, U> BorshSerializeAs<T> for TryFromInto<U>
480where
481    T: TryInto<U> + Clone,
482    <T as TryInto<U>>::Error: Display,
483    U: BorshSerialize,
484{
485    #[inline]
486    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
487    where
488        W: io::Write,
489    {
490        source
491            .clone()
492            .try_into()
493            .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?
494            .serialize(writer)
495    }
496}
497
498impl<T, U> BorshDeserializeAs<T> for TryFromInto<U>
499where
500    U: BorshDeserialize + TryInto<T>,
501    <U as TryInto<T>>::Error: Display,
502{
503    #[inline]
504    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
505    where
506        R: io::Read,
507    {
508        U::deserialize_reader(reader).and_then(|v| {
509            v.try_into()
510                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))
511        })
512    }
513}
514
515pub struct Or<T1: ?Sized, T2: ?Sized>(PhantomData<T1>, PhantomData<T2>);
516
517/// Reads/writes all remaining bytes without a length prefix.
518///
519/// Useful for fields that should consume the remainder of the input.
520///
521/// # Example
522/// ```
523/// use defuse_borsh_utils::{As, Remainder};
524/// use borsh::{BorshSerialize, BorshDeserialize};
525/// #[derive(BorshSerialize, BorshDeserialize)]
526/// struct S {
527///     #[borsh(
528///         serialize_with = "As::<Remainder>::serialize",
529///         deserialize_with = "As::<Remainder>::deserialize"
530///     )]
531///     pub data: Vec<u8>,
532/// }
533/// ```
534pub struct Remainder;
535
536impl<T> BorshSerializeAs<T> for Remainder
537where
538    T: AsRef<[u8]>,
539{
540    #[inline]
541    fn serialize_as<W>(source: &T, writer: &mut W) -> io::Result<()>
542    where
543        W: io::Write,
544    {
545        writer.write_all(source.as_ref())
546    }
547}
548
549impl<T> BorshDeserializeAs<T> for Remainder
550where
551    T: TryFrom<Vec<u8>>,
552    T::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
553{
554    #[inline]
555    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
556    where
557        R: io::Read,
558    {
559        let mut buf = Vec::new();
560        reader.read_to_end(&mut buf)?;
561        buf.try_into()
562            .map_err(|err: T::Error| io::Error::new(io::ErrorKind::InvalidData, err))
563    }
564}
565
566impl<T, As1, As2> BorshDeserializeAs<T> for Or<As1, As2>
567where
568    As1: BorshDeserializeAs<T> + ?Sized,
569    As2: BorshDeserializeAs<T> + ?Sized,
570{
571    #[inline]
572    fn deserialize_as<R>(reader: &mut R) -> io::Result<T>
573    where
574        R: io::Read,
575    {
576        let mut buf = Vec::new();
577        As1::deserialize_as(&mut reader.tee(&mut buf))
578            .or_else(|_| As2::deserialize_as(&mut buf.chain(reader)))
579    }
580}
581
582#[cfg(test)]
583mod tests;