Skip to main content

tlb/as/hashmap/
aug.rs

1use std::iter::once;
2
3use crate::{
4    Context, Error,
5    r#as::{ParseFully, Ref, Same},
6    bits::{
7        bitvec::{order::Msb0, slice::BitSlice, vec::BitVec},
8        de::BitReaderExt,
9        ser::BitWriterExt,
10    },
11    de::{CellDeserialize, CellDeserializeAs, CellParser, CellParserError},
12    ser::{CellBuilder, CellBuilderError, CellSerialize, CellSerializeAs},
13};
14use impl_tools::autoimpl;
15
16use super::hm_label::HmLabel;
17
18/// [`HashmapAugE n X Y`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmapauge).
19///
20/// When `E = ()` it is equivalent to [`HashmapE n X`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap)
21/// ```tlb
22/// ahme_empty$0 {n:#} {X:Type} {Y:Type} extra:Y = HashmapAugE n X Y;      
23/// ahme_root$1 {n:#} {X:Type} {Y:Type} root:^(HashmapAug n X Y)
24/// extra:Y = HashmapAugE n X Y;
25/// ```
26#[derive(Debug, Clone)]
27#[autoimpl(Deref using self.m)]
28#[autoimpl(DerefMut using self.m)]
29#[autoimpl(Default where E: Default)]
30pub struct HashmapAugE<T, E = ()> {
31    pub m: HashmapE<T, E>,
32    pub extra: E,
33}
34
35impl<T, AsT, E, AsE> CellSerializeAs<HashmapAugE<T, E>> for HashmapAugE<AsT, AsE>
36where
37    AsT: CellSerializeAs<T>,
38    AsT::Args: Clone,
39    AsE: CellSerializeAs<E>,
40    AsE::Args: Clone,
41{
42    /// (n, AsT::Args, AsE::Args)
43    type Args = (u32, AsT::Args, AsE::Args);
44
45    #[inline]
46    fn store_as(
47        source: &HashmapAugE<T, E>,
48        builder: &mut CellBuilder,
49        (n, node_args, extra_args): Self::Args,
50    ) -> Result<(), CellBuilderError> {
51        builder
52            .store_as::<_, &HashmapE<AsT, AsE>>(&source.m, (n, node_args, extra_args.clone()))?
53            // extra:Y
54            .store_as::<_, &AsE>(&source.extra, extra_args)
55            .context("extra")?;
56        Ok(())
57    }
58}
59
60impl<'de, T, AsT, E, AsE> CellDeserializeAs<'de, HashmapAugE<T, E>> for HashmapAugE<AsT, AsE>
61where
62    AsT: CellDeserializeAs<'de, T>,
63    AsT::Args: Clone,
64    AsE: CellDeserializeAs<'de, E>,
65    AsE::Args: Clone,
66{
67    /// (n, AsT::Args, AsE::Args)
68    type Args = (u32, AsT::Args, AsE::Args);
69
70    #[inline]
71    fn parse_as(
72        parser: &mut CellParser<'de>,
73        (n, node_args, extra_args): Self::Args,
74    ) -> Result<HashmapAugE<T, E>, CellParserError<'de>> {
75        Ok(HashmapAugE {
76            m: parser.parse_as::<_, HashmapE<AsT, AsE>>((n, node_args, extra_args.clone()))?,
77            // extra:Y
78            extra: parser.parse_as::<_, AsE>(extra_args).context("extra")?,
79        })
80    }
81}
82
83/// [`HashmapE n X`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap).  
84/// Type parameter `E` is optional and stands for `extra`, so it can be reused
85/// for [`HashmapAugE n X E`](HashmapAugE)
86/// ```tlb
87/// hme_empty$0 {n:#} {X:Type} = HashmapE n X;
88/// hme_root$1 {n:#} {X:Type} root:^(Hashmap n X) = HashmapE n X;
89/// ```
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub enum HashmapE<T, E = ()> {
92    Empty,
93    Root(Hashmap<T, E>),
94}
95
96impl<T, E> Default for HashmapE<T, E> {
97    #[inline]
98    fn default() -> Self {
99        Self::Empty
100    }
101}
102
103impl<T, E> HashmapE<T, E> {
104    /// Create empty hashmap
105    #[inline]
106    pub const fn new() -> Self {
107        Self::Empty
108    }
109
110    /// Return whether this hashmap is empty
111    #[inline]
112    pub const fn is_empty(&self) -> bool {
113        matches!(self, Self::Empty)
114    }
115
116    /// Return number of leaf nodes in this hashmap
117    #[inline]
118    pub fn len(&self) -> usize {
119        match self {
120            Self::Empty => 0,
121            Self::Root(root) => root.len(),
122        }
123    }
124
125    /// Returns whether this hashmap contains given key
126    #[inline]
127    pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
128        match self {
129            Self::Empty => false,
130            Self::Root(root) => root.contains_key(key),
131        }
132    }
133
134    /// Returns reference to leaf value associated with given key
135    #[inline]
136    pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
137        match self {
138            Self::Empty => None,
139            Self::Root(root) => root.get(key),
140        }
141    }
142
143    /// Returns mutable reference to leaf value associated with given key
144    #[inline]
145    pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
146        match self {
147            Self::Empty => None,
148            Self::Root(root) => root.get_mut(key),
149        }
150    }
151}
152
153impl<T, AsT, E, AsE> CellSerializeAs<HashmapE<T, E>> for HashmapE<AsT, AsE>
154where
155    AsT: CellSerializeAs<T>,
156    AsT::Args: Clone,
157    AsE: CellSerializeAs<E>,
158    AsE::Args: Clone,
159{
160    // (n, AsT::Args, AsE::Args)
161    type Args = (u32, AsT::Args, AsE::Args);
162
163    #[inline]
164    fn store_as(
165        source: &HashmapE<T, E>,
166        builder: &mut CellBuilder,
167        args: Self::Args,
168    ) -> Result<(), CellBuilderError> {
169        match source {
170            HashmapE::Empty => builder
171                // hme_empty$0
172                .pack(false, ())?,
173            HashmapE::Root(root) => builder
174                // hme_root$1
175                .pack(true, ())?
176                // root:^(Hashmap n X)
177                .store_as::<_, Ref<&Hashmap<AsT, AsE>>>(root, args)?,
178        };
179        Ok(())
180    }
181}
182
183impl<T, E> CellSerialize for HashmapE<T, E>
184where
185    T: CellSerialize,
186    T::Args: Clone,
187    E: CellSerialize,
188    E::Args: Clone,
189{
190    // (n, T::Args, E::Args)
191    type Args = (u32, T::Args, E::Args);
192
193    #[inline]
194    fn store(&self, builder: &mut CellBuilder, args: Self::Args) -> Result<(), CellBuilderError> {
195        builder.store_as::<_, Same>(self, args)?;
196        Ok(())
197    }
198}
199
200impl<'de, T, AsT, E, AsE> CellDeserializeAs<'de, HashmapE<T, E>> for HashmapE<AsT, AsE>
201where
202    AsT: CellDeserializeAs<'de, T>,
203    AsT::Args: Clone,
204    AsE: CellDeserializeAs<'de, E>,
205    AsE::Args: Clone,
206{
207    // (n, AsT::Args, AsE::Args)
208    type Args = (u32, AsT::Args, AsE::Args);
209
210    #[inline]
211    fn parse_as(
212        parser: &mut CellParser<'de>,
213        (n, node_args, extra_args): Self::Args,
214    ) -> Result<HashmapE<T, E>, CellParserError<'de>> {
215        Ok(match parser.unpack(())? {
216            // hme_empty$0
217            false => HashmapE::Empty,
218            // hme_root$1
219            true => parser
220                // root:^(Hashmap n X)
221                .parse_as::<_, Ref<ParseFully<Hashmap<AsT, AsE>>>>((n, node_args, extra_args))
222                .map(HashmapE::Root)?,
223        })
224    }
225}
226
227impl<'de, T> CellDeserialize<'de> for HashmapE<T>
228where
229    T: CellDeserialize<'de>,
230    T::Args: Clone,
231{
232    /// (n, T::Args)
233    type Args = (u32, T::Args);
234
235    #[inline]
236    fn parse(parser: &mut CellParser<'de>, args: Self::Args) -> Result<Self, CellParserError<'de>> {
237        parser.parse_as::<_, Same>(args)
238    }
239}
240
241impl<'de, T, As, C> CellDeserializeAs<'de, C> for HashmapE<As>
242where
243    C: IntoIterator<Item = (Key, T)> + Extend<(Key, T)> + Default, // IntoIterator used as type constraint for T
244    As: CellDeserializeAs<'de, T>,
245    As::Args: Clone,
246{
247    // (n, As::Args)
248    type Args = (u32, As::Args);
249
250    #[inline]
251    fn parse_as(
252        parser: &mut CellParser<'de>,
253        (n, node_args): Self::Args,
254    ) -> Result<C, CellParserError<'de>> {
255        Ok(match parser.unpack(())? {
256            // hme_empty$0
257            false => C::default(),
258            // hme_root$1
259            true => parser
260                // root:^(Hashmap n X)
261                .parse_as::<_, Ref<ParseFully<Hashmap<As, ()>>>>((n, node_args))?,
262        })
263    }
264}
265
266/// [`Hashmap n X`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap)  
267/// Type parameter `E` is optional and stands for `extra`, so it can be reused
268/// for [`HashmapAug n X E`](HashmapAugE)
269/// ```tlb
270/// hm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n)
271/// {n = (~m) + l} node:(HashmapNode m X) = Hashmap n X;
272/// ```
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct Hashmap<T, E = ()> {
275    pub(super) prefix: BitVec<u8, Msb0>,
276    pub(super) node: HashmapAugNode<T, E>,
277}
278
279impl<T, E> Hashmap<T, E> {
280    #[inline]
281    pub fn new(prefix: impl Into<BitVec<u8, Msb0>>, node: HashmapAugNode<T, E>) -> Self {
282        Self {
283            prefix: prefix.into(),
284            node,
285        }
286    }
287
288    #[inline]
289    pub fn prefix(&self) -> &BitSlice<u8, Msb0> {
290        &self.prefix
291    }
292
293    #[inline]
294    #[allow(clippy::len_without_is_empty)]
295    pub fn len(&self) -> usize {
296        self.node.len()
297    }
298
299    #[inline]
300    pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
301        key.as_ref()
302            .strip_prefix(&self.prefix)
303            .is_some_and(|key| self.node.contains_key(key))
304    }
305
306    #[inline]
307    pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
308        self.node.get(key.as_ref().strip_prefix(&self.prefix)?)
309    }
310
311    #[inline]
312    pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
313        self.node.get_mut(key.as_ref().strip_prefix(&self.prefix)?)
314    }
315}
316
317impl<T, AsT, E, AsE> CellSerializeAs<Hashmap<T, E>> for Hashmap<AsT, AsE>
318where
319    AsT: CellSerializeAs<T>,
320    AsT::Args: Clone,
321    AsE: CellSerializeAs<E>,
322    AsE::Args: Clone,
323{
324    /// (n, AsT::Args, AsE::Args)
325    type Args = (u32, AsT::Args, AsE::Args);
326
327    fn store_as(
328        source: &Hashmap<T, E>,
329        builder: &mut CellBuilder,
330        (n, node_args, extra_args): Self::Args,
331    ) -> Result<(), CellBuilderError> {
332        builder
333            // label:(HmLabel ~l n)
334            .pack_as::<_, &HmLabel>(source.prefix.as_bitslice(), n)
335            .context("label")?
336            // node:(HashmapNode m X)
337            .store_as::<_, &HashmapAugNode<AsT, AsE>>(
338                &source.node,
339                (
340                    // {n = (~m) + l}
341                    n - source.prefix.len() as u32,
342                    node_args,
343                    extra_args,
344                ),
345            )
346            .context("node")?;
347        Ok(())
348    }
349}
350
351impl<'de, T, AsT, E, AsE> CellDeserializeAs<'de, Hashmap<T, E>> for Hashmap<AsT, AsE>
352where
353    AsT: CellDeserializeAs<'de, T>,
354    AsT::Args: Clone,
355    AsE: CellDeserializeAs<'de, E>,
356    AsE::Args: Clone,
357{
358    /// (n, AsT::Args, AsE::Args)
359    type Args = (u32, AsT::Args, AsE::Args);
360
361    #[inline]
362    fn parse_as(
363        parser: &mut CellParser<'de>,
364        (n, node_args, extra_args): Self::Args,
365    ) -> Result<Hashmap<T, E>, CellParserError<'de>> {
366        // label:(HmLabel ~l n)
367        let prefix: BitVec<u8, Msb0> = parser.unpack_as::<_, HmLabel>(n).context("label")?;
368        // {n = (~m) + l}
369        let m = n - prefix.len() as u32;
370        Ok(Hashmap {
371            prefix,
372            // node:(HashmapNode m X)
373            node: parser
374                .parse_as::<_, HashmapAugNode<AsT, AsE>>((m, node_args, extra_args))
375                .context("node")?,
376        })
377    }
378}
379
380pub type Key = BitVec<u8, Msb0>;
381impl<'de, T, As, C> CellDeserializeAs<'de, C> for Hashmap<As>
382where
383    C: IntoIterator<Item = (Key, T)> + Extend<(Key, T)> + Default, // IntoIterator used as type constraint for T
384    As: CellDeserializeAs<'de, T>,
385    As::Args: Clone,
386{
387    /// (n, As::Args)
388    type Args = (u32, As::Args);
389
390    #[inline]
391    fn parse_as(
392        parser: &mut CellParser<'de>,
393        (n, args): Self::Args,
394    ) -> Result<C, CellParserError<'de>> {
395        let mut output = C::default();
396        let mut stack: Vec<(u32, Key, CellParser<'de>)> = Vec::new();
397
398        #[inline]
399        fn parse<'de, T, As, C>(
400            parser: &mut CellParser<'de>,
401            stack: &mut Vec<(u32, Key, CellParser<'de>)>,
402            output: &mut C,
403            n: u32,
404            mut prefix: Key,
405            args: As::Args,
406        ) -> Result<(), CellParserError<'de>>
407        where
408            C: Extend<(Key, T)>,
409            As: CellDeserializeAs<'de, T>,
410        {
411            // label:(HmLabel ~l n)
412            let next_prefix: BitVec<u8, Msb0> =
413                parser.unpack_as::<_, HmLabel>(n).context("label")?;
414            // {n = (~m) + l}
415            let m = n - next_prefix.len() as u32;
416
417            prefix.extend_from_bitslice(&next_prefix);
418
419            match m {
420                // bt_leaf$0
421                0 => output.extend(once((prefix, parser.parse_as::<_, As>(args)?))),
422                // bt_fork$1
423                1.. => stack.extend(
424                    parser
425                        .parse_as::<_, [Ref; 2]>(())?
426                        .into_iter()
427                        .enumerate()
428                        // HashmapNode (n + 1)
429                        .map(|(next_prefix, parser)| {
430                            let mut prefix = prefix.clone();
431                            prefix.push(next_prefix != 0);
432
433                            (m - 1, prefix, parser)
434                        })
435                        // inverse ordering
436                        .rev(),
437                ),
438            }
439            Ok(())
440        }
441
442        parse::<_, As, C>(
443            parser,
444            &mut stack,
445            &mut output,
446            n,
447            Key::default(),
448            args.clone(),
449        )?;
450
451        while let Some((n, prefix, mut parser)) = stack.pop() {
452            parse::<_, As, C>(
453                &mut parser,
454                &mut stack,
455                &mut output,
456                n,
457                prefix,
458                args.clone(),
459            )?;
460        }
461
462        Ok(output)
463    }
464}
465
466/// [`HashmapNode n X`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap)
467///
468/// Type parameter `E` is optional and stands for `extra`, so it can be reused
469/// for [`HashmapAugNode n X E`](HashmapAugNode)
470/// ```tlb
471/// hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X;
472/// hmn_fork#_ {n:#} {X:Type} left:^(Hashmap n X)
473///            right:^(Hashmap n X) = HashmapNode (n + 1) X;
474/// ```
475#[derive(Debug, Clone, PartialEq, Eq)]
476pub enum HashmapNode<T, E = ()> {
477    Leaf(T),
478    /// [left, right]
479    Fork([Box<Hashmap<T, E>>; 2]),
480}
481
482impl<T, E> HashmapNode<T, E> {
483    #[inline]
484    #[allow(clippy::len_without_is_empty)]
485    pub fn len(&self) -> usize {
486        match self {
487            Self::Leaf(_) => 1,
488            Self::Fork([l, r]) => l.len() + r.len(),
489        }
490    }
491
492    #[inline]
493    pub fn contains_key(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> bool {
494        let key = key.as_ref();
495        match self {
496            Self::Leaf(_) if key.is_empty() => true,
497            Self::Fork([left, right]) => {
498                let Some((is_right, key)) = key.split_first() else {
499                    return false;
500                };
501                if *is_right { right } else { left }.contains_key(key)
502            }
503            _ => false,
504        }
505    }
506
507    #[inline]
508    pub fn get(&self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&T> {
509        let key = key.as_ref();
510        match self {
511            Self::Leaf(v) if key.is_empty() => Some(v),
512            Self::Fork([left, right]) => {
513                let (is_right, key) = key.split_first()?;
514                if *is_right { right } else { left }.get(key)
515            }
516            _ => None,
517        }
518    }
519
520    #[inline]
521    pub fn get_mut(&mut self, key: impl AsRef<BitSlice<u8, Msb0>>) -> Option<&mut T> {
522        let key = key.as_ref();
523        match self {
524            Self::Leaf(v) if key.is_empty() => Some(v),
525            Self::Fork([left, right]) => {
526                let (is_right, key) = key.split_first()?;
527                if *is_right { right } else { left }.get_mut(key)
528            }
529            _ => None,
530        }
531    }
532}
533
534impl<T, AsT, E, AsE> CellSerializeAs<HashmapNode<T, E>> for HashmapNode<AsT, AsE>
535where
536    AsT: CellSerializeAs<T>,
537    AsT::Args: Clone,
538    AsE: CellSerializeAs<E>,
539    AsE::Args: Clone,
540{
541    // (n, AsT::Args, AsE::Args)
542    type Args = (u32, AsT::Args, AsE::Args);
543
544    fn store_as(
545        source: &HashmapNode<T, E>,
546        builder: &mut CellBuilder,
547        (n, node_args, extra_args): Self::Args,
548    ) -> Result<(), CellBuilderError> {
549        match source {
550            HashmapNode::Leaf(value) => {
551                if n != 0 {
552                    return Err(CellBuilderError::custom(format!(
553                        "key is too small, {n} more bits required"
554                    )));
555                }
556                // hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X;
557                builder.store_as::<_, &AsT>(value, node_args)?
558            }
559            HashmapNode::Fork(fork) => {
560                if n == 0 {
561                    return Err(CellBuilderError::custom("key is too long"));
562                }
563                // hmn_fork#_ {n:#} {X:Type} left:^(Hashmap n X)
564                // right:^(Hashmap n X) = HashmapNode (n + 1) X;
565                builder.store_as::<_, &[Box<Ref<Hashmap<AsT, AsE>>>; 2]>(
566                    fork,
567                    (n - 1, node_args, extra_args),
568                )?
569            }
570        };
571        Ok(())
572    }
573}
574
575impl<'de, T, AsT, E, AsE> CellDeserializeAs<'de, HashmapNode<T, E>> for HashmapNode<AsT, AsE>
576where
577    AsT: CellDeserializeAs<'de, T>,
578    AsT::Args: Clone,
579    AsE: CellDeserializeAs<'de, E>,
580    AsE::Args: Clone,
581{
582    /// (n + 1, AsT::Args, AsE::Args)
583    type Args = (u32, AsT::Args, AsE::Args);
584
585    #[inline]
586    fn parse_as(
587        parser: &mut CellParser<'de>,
588        (n, node_args, extra_args): Self::Args,
589    ) -> Result<HashmapNode<T, E>, CellParserError<'de>> {
590        if n == 0 {
591            // hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X;
592            return parser.parse_as::<_, AsT>(node_args).map(HashmapNode::Leaf);
593        }
594
595        Ok(HashmapNode::Fork(
596            parser
597                // left:^(Hashmap n X) right:^(Hashmap n X)
598                .parse_as::<_, [Box<Ref<ParseFully<Hashmap<AsT, AsE>>>>; 2]>((
599                    n - 1,
600                    node_args,
601                    extra_args,
602                ))?,
603        ))
604    }
605}
606
607/// [`HashmapAugNode n X Y`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmapauge)
608///
609/// When `E = ()` it is equivalent to [`HashmapNode n X`](https://docs.ton.org/develop/data-formats/tl-b-types#hashmap)
610/// ```tlb
611/// ahmn_leaf#_ {X:Type} {Y:Type} extra:Y value:X = HashmapAugNode 0 X Y;
612/// ahmn_fork#_ {n:#} {X:Type} {Y:Type} left:^(HashmapAug n X Y)
613/// right:^(HashmapAug n X Y) extra:Y = HashmapAugNode (n + 1) X Y;
614/// ```
615#[derive(Debug, Clone, PartialEq, Eq)]
616#[autoimpl(Deref using self.node)]
617#[autoimpl(DerefMut using self.node)]
618pub struct HashmapAugNode<T, E = ()> {
619    pub node: HashmapNode<T, E>,
620    pub extra: E,
621}
622
623impl<T, E> HashmapAugNode<T, E> {
624    #[inline]
625    pub const fn new(node: HashmapNode<T, E>, extra: E) -> Self {
626        Self { node, extra }
627    }
628}
629
630impl<T, AsT, E, AsE> CellSerializeAs<HashmapAugNode<T, E>> for HashmapAugNode<AsT, AsE>
631where
632    AsT: CellSerializeAs<T>,
633    AsT::Args: Clone,
634    AsE: CellSerializeAs<E>,
635    AsE::Args: Clone,
636{
637    /// (n + 1, AsT::Args, AsE::Args)
638    type Args = (u32, AsT::Args, AsE::Args);
639
640    fn store_as(
641        source: &HashmapAugNode<T, E>,
642        builder: &mut CellBuilder,
643        (n, node_args, extra_args): Self::Args,
644    ) -> Result<(), CellBuilderError> {
645        builder
646            // extra:Y
647            .store_as::<_, &AsE>(&source.extra, extra_args.clone())?
648            .store_as::<_, &HashmapNode<AsT, AsE>>(&source.node, (n, node_args, extra_args))?;
649        Ok(())
650    }
651}
652
653impl<'de, T, AsT, E, AsE> CellDeserializeAs<'de, HashmapAugNode<T, E>> for HashmapAugNode<AsT, AsE>
654where
655    AsT: CellDeserializeAs<'de, T>,
656    AsT::Args: Clone,
657    AsE: CellDeserializeAs<'de, E>,
658    AsE::Args: Clone,
659{
660    /// (n + 1, AsT::Args, AsE::Args)
661    type Args = (u32, AsT::Args, AsE::Args);
662
663    fn parse_as(
664        parser: &mut CellParser<'de>,
665        (n, node_args, extra_args): Self::Args,
666    ) -> Result<HashmapAugNode<T, E>, CellParserError<'de>> {
667        Ok(HashmapAugNode {
668            // extra:Y
669            extra: parser.parse_as::<_, AsE>(extra_args.clone())?,
670            node: parser.parse_as::<_, HashmapNode<AsT, AsE>>((n, node_args, extra_args))?,
671        })
672    }
673}
674
675#[cfg(test)]
676mod tests {
677    use crate::{
678        Cell, Data,
679        bits::bitvec::{bits, order::Msb0, view::AsBits},
680        ser::{CellSerializeExt, CellSerializeWrapAsExt},
681    };
682    use std::collections::{BTreeMap, HashMap};
683
684    use super::*;
685
686    #[test]
687    fn parse() {
688        let cell = given_cell_from_example();
689
690        let hm: HashmapE<u16> = cell
691            .parse_fully_as::<_, HashmapE<Data, Same>>((8, (), ()))
692            .unwrap();
693
694        assert_eq!(hm.len(), 3);
695        // 1 -> 777
696        assert_eq!(hm.get(1u8.to_be_bytes().as_bits()), Some(&777));
697        // 17 -> 111
698        assert_eq!(hm.get(17u8.to_be_bytes().as_bits()), Some(&111));
699        // 128 -> 777
700        assert_eq!(hm.get(128u8.to_be_bytes().as_bits()), Some(&777));
701
702        let mut builder = Cell::builder();
703        builder
704            .store_as::<_, HashmapE<Data, Same>>(hm, (8, (), ()))
705            .unwrap();
706        let got = builder.into_cell();
707        assert_eq!(got, cell);
708    }
709
710    #[test]
711    fn hashmape_parse_as_std_hashmap() {
712        let cell = given_cell_from_example();
713
714        let hm: HashMap<Key, u16> = cell.parse_fully_as::<_, HashmapE<Data>>((8, ())).unwrap();
715
716        assert_eq!(hm.len(), 3);
717        // 1 -> 777
718        assert_eq!(hm.get(1u8.to_be_bytes().as_bits()), Some(&777));
719        // 17 -> 111
720        assert_eq!(hm.get(17u8.to_be_bytes().as_bits()), Some(&111));
721        // 128 -> 777
722        assert_eq!(hm.get(128u8.to_be_bytes().as_bits()), Some(&777));
723    }
724
725    #[test]
726    fn hashmape_parse_as_std_btreemap() {
727        let cell = given_cell_from_example();
728
729        let hm: BTreeMap<Key, u16> = cell.parse_fully_as::<_, HashmapE<Data>>((8, ())).unwrap();
730
731        assert_eq!(hm.len(), 3);
732        // 1 -> 777
733        assert_eq!(hm.get(1u8.to_be_bytes().as_bits()), Some(&777));
734        // 17 -> 111
735        assert_eq!(hm.get(17u8.to_be_bytes().as_bits()), Some(&111));
736        // 128 -> 777
737        assert_eq!(hm.get(128u8.to_be_bytes().as_bits()), Some(&777));
738    }
739
740    /// See <https://docs.ton.org/develop/data-formats/tl-b-types#hashmap-parsing-example>
741    fn given_cell_from_example() -> Cell {
742        (
743            bits![u8, Msb0; 1].wrap_as::<Data>(),
744            (
745                bits![u8, Msb0; 0,0].wrap_as::<Data>(),
746                (
747                    // original example uses 0b1001000 due to hml_long$10,
748                    // but hml_short$0 is more efficient here
749                    bits![u8, Msb0; 0,1,1,0,0,0].wrap_as::<Data>(),
750                    bits![u8, Msb0; 1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1]
751                        .wrap_as::<Ref<Data>>(),
752                    bits![u8, Msb0; 1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1]
753                        .wrap_as::<Ref<Data>>(),
754                )
755                    .wrap_as::<Ref>(),
756                // original example uses 0b1011100000000000001100001001
757                // due to hml_long$10, but hml_same$11 is more efficient
758                bits![u8, Msb0; 1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1].wrap_as::<Ref<Data>>(),
759            )
760                .wrap_as::<Ref>(),
761        )
762            .to_cell(((), ((), ((), (), ()), ())))
763            .unwrap()
764    }
765}