Skip to main content

tlbits/ser/
as.rs

1use std::{borrow::Cow, rc::Rc, sync::Arc};
2
3use bitvec::{order::Msb0, vec::BitVec};
4use either::Either;
5
6use crate::{
7    StringError,
8    r#as::{AsWrap, Same},
9};
10
11use super::{BitPack, BitWriter, BitWriterExt};
12
13/// Adapter to **ser**ialize `T`.  
14///
15/// This approach is heavily inspired by
16/// [serde_with](https://docs.rs/serde_with/latest/serde_with).
17/// Please, read their docs for more usage examples.
18pub trait BitPackAs<T: ?Sized> {
19    /// Arguments to be passed in runtime
20    type Args;
21
22    /// Packs the value with args using an adapter
23    fn pack_as<W>(source: &T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
24    where
25        W: BitWriter + ?Sized;
26}
27
28/// **Ser**ialize given value into [`BitVec`] with argmuments using an adapter
29#[inline]
30pub fn pack_as<T, As>(value: T, args: As::Args) -> Result<BitVec<u8, Msb0>, StringError>
31where
32    As: BitPackAs<T> + ?Sized,
33{
34    let mut writer = BitVec::new();
35    writer.pack_as::<_, As>(value, args)?;
36    Ok(writer)
37}
38
39impl<'a, T, As> BitPackAs<&'a T> for &'a As
40where
41    As: BitPackAs<T> + ?Sized,
42    T: ?Sized,
43{
44    type Args = As::Args;
45
46    #[inline]
47    fn pack_as<W>(source: &&'a T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
48    where
49        W: BitWriter + ?Sized,
50    {
51        AsWrap::<&T, As>::new(source).pack(writer, args)
52    }
53}
54
55impl<'a, T, As> BitPackAs<&'a mut T> for &'a mut As
56where
57    As: BitPackAs<T> + ?Sized,
58    T: ?Sized,
59{
60    type Args = As::Args;
61
62    #[inline]
63    fn pack_as<W>(source: &&'a mut T, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
64    where
65        W: BitWriter + ?Sized,
66    {
67        AsWrap::<&T, As>::new(source).pack(writer, args)
68    }
69}
70
71impl<T, As> BitPackAs<[T]> for [As]
72where
73    As: BitPackAs<T>,
74    As::Args: Clone,
75{
76    type Args = As::Args;
77
78    #[inline]
79    fn pack_as<W>(source: &[T], writer: &mut W, args: Self::Args) -> Result<(), W::Error>
80    where
81        W: BitWriter + ?Sized,
82    {
83        writer.pack_many_as::<_, &As>(source, args)?;
84        Ok(())
85    }
86}
87
88impl<T, As, const N: usize> BitPackAs<[T; N]> for [As; N]
89where
90    As: BitPackAs<T>,
91    As::Args: Clone,
92{
93    type Args = As::Args;
94
95    #[inline]
96    fn pack_as<W>(source: &[T; N], writer: &mut W, args: Self::Args) -> Result<(), W::Error>
97    where
98        W: BitWriter + ?Sized,
99    {
100        <[As]>::pack_as(source.as_slice(), writer, args)
101    }
102}
103
104macro_rules! impl_bit_pack_as_for_tuple {
105    ($($t:ident as $a:ident:$n:tt),*) => {
106        impl<$($t, $a),*> BitPackAs<($($t,)*)> for ($($a,)*)
107        where $(
108            $a: BitPackAs<$t>,
109        )*
110        {
111            type Args = ($($a::Args,)*);
112
113            #[inline]
114            #[allow(unused_variables)]
115            fn pack_as<W>(source: &($($t,)*), writer: &mut W, args: Self::Args) -> Result<(), W::Error>
116            where
117                W: BitWriter + ?Sized,
118            {$(
119                $a::pack_as(&source.$n, writer, args.$n)?;)*
120                Ok(())
121            }
122        }
123    };
124}
125impl_bit_pack_as_for_tuple!();
126impl_bit_pack_as_for_tuple!(T0 as As0:0);
127impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1);
128impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2);
129impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3);
130impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4);
131impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5);
132impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6);
133impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7);
134impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7,T8 as As8:8);
135impl_bit_pack_as_for_tuple!(T0 as As0:0,T1 as As1:1,T2 as As2:2,T3 as As3:3,T4 as As4:4,T5 as As5:5,T6 as As6:6,T7 as As7:7,T8 as As8:8,T9 as As9:9);
136
137impl<T, As> BitPackAs<Rc<T>> for Box<As>
138where
139    As: BitPackAs<T> + ?Sized,
140{
141    type Args = As::Args;
142
143    #[inline]
144    fn pack_as<W>(source: &Rc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
145    where
146        W: BitWriter + ?Sized,
147    {
148        AsWrap::<&T, As>::new(source).pack(writer, args)
149    }
150}
151
152impl<T, As> BitPackAs<Rc<T>> for Rc<As>
153where
154    As: BitPackAs<T> + ?Sized,
155{
156    type Args = As::Args;
157
158    #[inline]
159    fn pack_as<W>(source: &Rc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
160    where
161        W: BitWriter + ?Sized,
162    {
163        AsWrap::<&T, As>::new(source).pack(writer, args)
164    }
165}
166
167impl<T, As> BitPackAs<Arc<T>> for Arc<As>
168where
169    As: BitPackAs<T> + ?Sized,
170{
171    type Args = As::Args;
172
173    #[inline]
174    fn pack_as<W>(source: &Arc<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
175    where
176        W: BitWriter + ?Sized,
177    {
178        AsWrap::<&T, As>::new(source).pack(writer, args)
179    }
180}
181
182impl<'a, T, As> BitPackAs<Cow<'a, T>> for Cow<'a, As>
183where
184    T: ToOwned + ?Sized,
185    As: ToOwned + BitPackAs<T> + ?Sized,
186{
187    type Args = As::Args;
188
189    #[inline]
190    fn pack_as<W>(source: &Cow<'a, T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
191    where
192        W: BitWriter + ?Sized,
193    {
194        AsWrap::<&T, As>::new(source).pack(writer, args)
195    }
196}
197
198/// Implementation of [`Either X Y`](https://docs.ton.org/develop/data-formats/tl-b-types#either):
199/// ```tlb
200/// left$0 {X:Type} {Y:Type} value:X = Either X Y;
201/// right$1 {X:Type} {Y:Type} value:Y = Either X Y;
202/// ```
203impl<Left, Right, AsLeft, AsRight> BitPackAs<Either<Left, Right>> for Either<AsLeft, AsRight>
204where
205    AsLeft: BitPackAs<Left>,
206    AsRight: BitPackAs<Right>,
207{
208    type Args = (AsLeft::Args, AsRight::Args);
209
210    #[inline]
211    fn pack_as<W>(
212        source: &Either<Left, Right>,
213        writer: &mut W,
214        args: Self::Args,
215    ) -> Result<(), W::Error>
216    where
217        W: BitWriter + ?Sized,
218    {
219        source
220            .as_ref()
221            .map_either(AsWrap::<&Left, AsLeft>::new, AsWrap::<&Right, AsRight>::new)
222            .pack(writer, args)
223    }
224}
225
226impl<T, As> BitPackAs<Option<T>> for Either<(), As>
227where
228    As: BitPackAs<T>,
229{
230    type Args = As::Args;
231
232    #[inline]
233    fn pack_as<W>(source: &Option<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
234    where
235        W: BitWriter + ?Sized,
236    {
237        Either::<Same, &As>::pack_as(
238            &match source.as_ref() {
239                None => Either::Left(()),
240                Some(v) => Either::Right(v),
241            },
242            writer,
243            ((), args),
244        )
245    }
246}
247
248/// Implementation of [`Maybe X`](https://docs.ton.org/develop/data-formats/tl-b-types#maybe):
249/// ```tlb
250/// nothing$0 {X:Type} = Maybe X;
251/// just$1 {X:Type} value:X = Maybe X;
252/// ```
253impl<T, As> BitPackAs<Option<T>> for Option<As>
254where
255    As: BitPackAs<T>,
256{
257    type Args = As::Args;
258
259    #[inline]
260    fn pack_as<W>(source: &Option<T>, writer: &mut W, args: Self::Args) -> Result<(), W::Error>
261    where
262        W: BitWriter + ?Sized,
263    {
264        source
265            .as_ref()
266            .map(AsWrap::<&T, As>::new)
267            .pack(writer, args)
268    }
269}
270
271pub trait BitPackWrapAsExt {
272    #[inline]
273    fn wrap_as<As>(&self) -> AsWrap<&'_ Self, As>
274    where
275        As: BitPackAs<Self> + ?Sized,
276    {
277        AsWrap::new(self)
278    }
279}
280impl<T> BitPackWrapAsExt for T {}