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::{Context, StringError, r#as::AsWrap};
7
8use super::{BitPack, BitWriter, BitWriterExt};
9
10/// Adapter to **ser**ialize `T`.  
11/// See [`as`](crate::as) module-level documentation for more.
12///
13/// For dynamic arguments, see
14/// [`BitPackAsWithArgs`](super::args::as::BitPackAsWithArgs).
15pub trait BitPackAs<T: ?Sized> {
16    /// Packs given value using an adapter.
17    fn pack_as<W>(source: &T, writer: W) -> Result<(), W::Error>
18    where
19        W: BitWriter;
20}
21
22/// **Ser**ialize given value into [`BitVec`] using an adapter
23#[inline]
24pub fn pack_as<T, As>(value: T) -> Result<BitVec<u8, Msb0>, StringError>
25where
26    As: BitPackAs<T> + ?Sized,
27{
28    let mut writer = BitVec::new();
29    writer.pack_as::<_, As>(value)?;
30    Ok(writer)
31}
32
33impl<'a, T, As> BitPackAs<&'a T> for &'a As
34where
35    As: BitPackAs<T> + ?Sized,
36    T: ?Sized,
37{
38    #[inline]
39    fn pack_as<W>(source: &&T, writer: W) -> Result<(), W::Error>
40    where
41        W: BitWriter,
42    {
43        AsWrap::<&T, As>::new(source).pack(writer)
44    }
45}
46
47impl<'a, T, As> BitPackAs<&'a mut T> for &'a mut As
48where
49    As: BitPackAs<T> + ?Sized,
50    T: ?Sized,
51{
52    #[inline]
53    fn pack_as<W>(source: &&mut T, writer: W) -> Result<(), W::Error>
54    where
55        W: BitWriter,
56    {
57        AsWrap::<&T, As>::new(source).pack(writer)
58    }
59}
60
61impl<T, As> BitPackAs<[T]> for [As]
62where
63    As: BitPackAs<T>,
64{
65    #[inline]
66    fn pack_as<W>(source: &[T], mut writer: W) -> Result<(), W::Error>
67    where
68        W: BitWriter,
69    {
70        for (i, v) in source.iter().enumerate() {
71            writer
72                .pack_as::<&T, &As>(v)
73                .with_context(|| format!("[{i}]"))?;
74        }
75        Ok(())
76    }
77}
78
79impl<T, As, const N: usize> BitPackAs<[T; N]> for [As; N]
80where
81    As: BitPackAs<T>,
82{
83    #[inline]
84    fn pack_as<W>(source: &[T; N], mut writer: W) -> Result<(), W::Error>
85    where
86        W: BitWriter,
87    {
88        writer.pack_as::<&[T], &[As]>(source)?;
89        Ok(())
90    }
91}
92
93macro_rules! impl_bit_pack_as_for_tuple {
94    ($($n:tt:$t:ident as $a:ident),+) => {
95        impl<$($t, $a),+> BitPackAs<($($t,)+)> for ($($a,)+)
96        where $(
97            $a: BitPackAs<$t>,
98        )+
99        {
100            #[inline]
101            fn pack_as<W>(source: &($($t,)+), mut writer: W) -> Result<(), W::Error>
102            where
103                W: BitWriter,
104            {
105                writer$(
106                    .pack_as::<&$t, &$a>(&source.$n)?)+;
107                Ok(())
108            }
109        }
110    };
111}
112impl_bit_pack_as_for_tuple!(0:T0 as As0);
113impl_bit_pack_as_for_tuple!(0:T0 as As0,1:T1 as As1);
114impl_bit_pack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2);
115impl_bit_pack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3);
116impl_bit_pack_as_for_tuple!(0:T0 as As0,1:T1 as As1,2:T2 as As2,3:T3 as As3,4:T4 as As4);
117impl_bit_pack_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);
118impl_bit_pack_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);
119impl_bit_pack_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);
120impl_bit_pack_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);
121impl_bit_pack_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);
122
123impl<T, As> BitPackAs<Box<T>> for Box<As>
124where
125    As: BitPackAs<T> + ?Sized,
126{
127    #[inline]
128    fn pack_as<W>(source: &Box<T>, writer: W) -> Result<(), W::Error>
129    where
130        W: BitWriter,
131    {
132        AsWrap::<&T, As>::new(source).pack(writer)
133    }
134}
135
136impl<T, As> BitPackAs<Rc<T>> for Rc<As>
137where
138    As: BitPackAs<T> + ?Sized,
139{
140    #[inline]
141    fn pack_as<W>(source: &Rc<T>, writer: W) -> Result<(), W::Error>
142    where
143        W: BitWriter,
144    {
145        AsWrap::<&T, As>::new(source).pack(writer)
146    }
147}
148
149impl<T, As> BitPackAs<Arc<T>> for Arc<As>
150where
151    As: BitPackAs<T> + ?Sized,
152{
153    #[inline]
154    fn pack_as<W>(source: &Arc<T>, writer: W) -> Result<(), W::Error>
155    where
156        W: BitWriter,
157    {
158        AsWrap::<&T, As>::new(source).pack(writer)
159    }
160}
161
162impl<'a, T, As> BitPackAs<Cow<'a, T>> for Cow<'a, As>
163where
164    T: ToOwned + ?Sized,
165    As: ToOwned + BitPackAs<T> + ?Sized,
166{
167    #[inline]
168    fn pack_as<W>(source: &Cow<'a, T>, writer: W) -> Result<(), W::Error>
169    where
170        W: BitWriter,
171    {
172        AsWrap::<&T, As>::new(source).pack(writer)
173    }
174}
175
176/// Implementation of [`Either X Y`](https://docs.ton.org/develop/data-formats/tl-b-types#either):
177/// ```tlb
178/// left$0 {X:Type} {Y:Type} value:X = Either X Y;
179/// right$1 {X:Type} {Y:Type} value:Y = Either X Y;
180/// ```
181impl<Left, Right, AsLeft, AsRight> BitPackAs<Either<Left, Right>> for Either<AsLeft, AsRight>
182where
183    AsLeft: BitPackAs<Left>,
184    AsRight: BitPackAs<Right>,
185{
186    #[inline]
187    fn pack_as<W>(source: &Either<Left, Right>, writer: W) -> Result<(), W::Error>
188    where
189        W: BitWriter,
190    {
191        source
192            .as_ref()
193            .map_either(AsWrap::<&Left, AsLeft>::new, AsWrap::<&Right, AsRight>::new)
194            .pack(writer)
195    }
196}
197
198impl<T, As> BitPackAs<Option<T>> for Either<(), As>
199where
200    As: BitPackAs<T>,
201{
202    #[inline]
203    fn pack_as<W>(source: &Option<T>, writer: W) -> Result<(), W::Error>
204    where
205        W: BitWriter,
206    {
207        match source.as_ref() {
208            None => Either::Left(()),
209            Some(v) => Either::Right(AsWrap::<&T, As>::new(v)),
210        }
211        .pack(writer)
212    }
213}
214
215/// Implementation of [`Maybe X`](https://docs.ton.org/develop/data-formats/tl-b-types#maybe):
216/// ```tlb
217/// nothing$0 {X:Type} = Maybe X;
218/// just$1 {X:Type} value:X = Maybe X;
219/// ```
220impl<T, As> BitPackAs<Option<T>> for Option<As>
221where
222    As: BitPackAs<T>,
223{
224    #[inline]
225    fn pack_as<W>(source: &Option<T>, writer: W) -> Result<(), W::Error>
226    where
227        W: BitWriter,
228    {
229        source.as_ref().map(AsWrap::<&T, As>::new).pack(writer)
230    }
231}
232
233pub trait BitPackWrapAsExt {
234    #[inline]
235    fn wrap_as<As>(&self) -> AsWrap<&'_ Self, As>
236    where
237        As: BitPackAs<Self> + ?Sized,
238    {
239        AsWrap::new(self)
240    }
241}
242impl<T> BitPackWrapAsExt for T {}