tonlib_core_anychain/cell/
builder.rs

1use std::collections::HashMap;
2use std::ops::Add;
3use std::sync::Arc;
4
5use bitstream_io::{BigEndian, BitWrite, BitWriter};
6use num_bigint::{BigInt, BigUint, Sign};
7use num_traits::{One, Zero};
8
9use crate::cell::dict::{DictBuilder, ValWriter};
10use crate::cell::error::{MapTonCellError, TonCellError};
11use crate::cell::{ArcCell, Cell, CellParser};
12use crate::TonAddress;
13
14pub(crate) const MAX_CELL_BITS: usize = 1023;
15pub(crate) const MAX_CELL_REFERENCES: usize = 4;
16pub(crate) const MAX_LEVEL_MASK: u32 = 3;
17
18pub struct CellBuilder {
19    bit_writer: BitWriter<Vec<u8>, BigEndian>,
20    bits_to_write: usize,
21    references: Vec<ArcCell>,
22    is_cell_exotic: bool,
23}
24
25#[derive(Clone, Debug, PartialEq, Copy)]
26pub enum EitherCellLayout {
27    Native,
28    ToRef,
29    ToCell,
30}
31
32impl CellBuilder {
33    pub fn new() -> CellBuilder {
34        let bit_writer = BitWriter::endian(Vec::new(), BigEndian);
35        CellBuilder {
36            bit_writer,
37            bits_to_write: 0,
38            references: Vec::new(),
39            is_cell_exotic: false,
40        }
41    }
42
43    pub fn set_cell_is_exotic(&mut self, val: bool) {
44        self.is_cell_exotic = val;
45    }
46
47    pub fn store_bit(&mut self, val: bool) -> Result<&mut Self, TonCellError> {
48        self.bit_writer.write_bit(val).map_cell_builder_error()?;
49        self.bits_to_write += 1;
50        Ok(self)
51    }
52
53    pub fn store_u8(&mut self, bit_len: usize, val: u8) -> Result<&mut Self, TonCellError> {
54        self.bit_writer
55            .write(bit_len as u32, val)
56            .map_cell_builder_error()?;
57        self.bits_to_write += bit_len;
58        Ok(self)
59    }
60
61    pub fn store_i8(&mut self, bit_len: usize, val: i8) -> Result<&mut Self, TonCellError> {
62        self.bit_writer
63            .write(bit_len as u32, val)
64            .map_cell_builder_error()?;
65        self.bits_to_write += bit_len;
66        Ok(self)
67    }
68
69    pub fn store_u32(&mut self, bit_len: usize, val: u32) -> Result<&mut Self, TonCellError> {
70        self.bit_writer
71            .write(bit_len as u32, val)
72            .map_cell_builder_error()?;
73        self.bits_to_write += bit_len;
74        Ok(self)
75    }
76
77    pub fn store_i32(&mut self, bit_len: usize, val: i32) -> Result<&mut Self, TonCellError> {
78        self.bit_writer
79            .write(bit_len as u32, val)
80            .map_cell_builder_error()?;
81        self.bits_to_write += bit_len;
82        Ok(self)
83    }
84
85    pub fn store_u64(&mut self, bit_len: usize, val: u64) -> Result<&mut Self, TonCellError> {
86        self.bit_writer
87            .write(bit_len as u32, val)
88            .map_cell_builder_error()?;
89        self.bits_to_write += bit_len;
90        Ok(self)
91    }
92
93    pub fn store_i64(&mut self, bit_len: usize, val: i64) -> Result<&mut Self, TonCellError> {
94        self.bit_writer
95            .write(bit_len as u32, val)
96            .map_cell_builder_error()?;
97        self.bits_to_write += bit_len;
98        Ok(self)
99    }
100
101    pub fn store_uint(&mut self, bit_len: usize, val: &BigUint) -> Result<&mut Self, TonCellError> {
102        let minimum_bits_needed = if val.is_zero() { 1 } else { val.bits() } as usize;
103        if minimum_bits_needed > bit_len {
104            return Err(TonCellError::cell_builder_error(format!(
105                "Value {} doesn't fit in {} bits (takes {} bits)",
106                val, bit_len, minimum_bits_needed
107            )));
108        }
109
110        let value_bytes = val.to_bytes_be();
111        let first_byte_bit_size = bit_len - (value_bytes.len() - 1) * 8;
112
113        for _ in 0..(first_byte_bit_size - 1) / 32 {
114            // fill full-bytes padding
115            self.store_u32(32, 0u32)?;
116        }
117
118        // fill first byte with required size
119        if first_byte_bit_size % 32 == 0 {
120            self.store_u32(32, value_bytes[0] as u32)?;
121        } else {
122            self.store_u32(first_byte_bit_size % 32, value_bytes[0] as u32)
123                .map_cell_builder_error()?;
124        }
125
126        // fill remaining bytes
127        for byte in value_bytes.iter().skip(1) {
128            self.store_u8(8, *byte).map_cell_builder_error()?;
129        }
130        Ok(self)
131    }
132
133    pub fn store_int(&mut self, bit_len: usize, val: &BigInt) -> Result<&mut Self, TonCellError> {
134        let (sign, mag) = val.clone().into_parts();
135        let bit_len = bit_len - 1; // reserve 1 bit for sign
136        if bit_len < mag.bits() as usize {
137            return Err(TonCellError::cell_builder_error(format!(
138                "Value {} doesn't fit in {} bits (takes {} bits)",
139                val,
140                bit_len,
141                mag.bits()
142            )));
143        }
144        if sign == Sign::Minus {
145            self.store_byte(1)?;
146            self.store_uint(bit_len, &extend_and_invert_bits(bit_len, &mag)?)?;
147        } else {
148            self.store_byte(0)?;
149            self.store_uint(bit_len, &mag)?;
150        };
151        Ok(self)
152    }
153
154    pub fn store_byte(&mut self, val: u8) -> Result<&mut Self, TonCellError> {
155        self.store_u8(8, val)
156    }
157
158    pub fn store_slice(&mut self, slice: &[u8]) -> Result<&mut Self, TonCellError> {
159        for val in slice {
160            self.store_byte(*val)?;
161        }
162        Ok(self)
163    }
164
165    pub fn store_bits(&mut self, bit_len: usize, slice: &[u8]) -> Result<&mut Self, TonCellError> {
166        let full_bytes = bit_len / 8;
167        self.store_slice(&slice[0..full_bytes])?;
168        let last_byte_len = bit_len % 8;
169        if last_byte_len != 0 {
170            let last_byte = slice[full_bytes] >> (8 - last_byte_len);
171            self.store_u8(last_byte_len, last_byte)?;
172        }
173        Ok(self)
174    }
175
176    pub fn store_string(&mut self, val: &str) -> Result<&mut Self, TonCellError> {
177        self.store_slice(val.as_bytes())
178    }
179
180    pub fn store_coins(&mut self, val: &BigUint) -> Result<&mut Self, TonCellError> {
181        if val.is_zero() {
182            self.store_u8(4, 0)
183        } else {
184            let num_bytes = (val.bits() as usize + 7) / 8;
185            self.store_u8(4, num_bytes as u8)?;
186            self.store_uint(num_bytes * 8, val)
187        }
188    }
189
190    /// Stores address without optimizing hole address
191    pub fn store_raw_address(&mut self, val: &TonAddress) -> Result<&mut Self, TonCellError> {
192        self.store_u8(2, 0b10u8)?;
193        self.store_bit(false)?;
194        let wc = (val.workchain & 0xff) as u8;
195        self.store_u8(8, wc)?;
196        self.store_slice(&val.hash_part)?;
197        Ok(self)
198    }
199
200    /// Stores address optimizing hole address two to bits
201    pub fn store_address(&mut self, val: &TonAddress) -> Result<&mut Self, TonCellError> {
202        if val == &TonAddress::NULL {
203            self.store_u8(2, 0)?;
204        } else {
205            self.store_raw_address(val)?;
206        }
207        Ok(self)
208    }
209
210    /// Adds reference to an existing `Cell`.
211    ///
212    /// The reference is passed as `ArcCell` so it might be references from other cells.
213    pub fn store_reference(&mut self, cell: &ArcCell) -> Result<&mut Self, TonCellError> {
214        let ref_count = self.references.len() + 1;
215        if ref_count > 4 {
216            return Err(TonCellError::cell_builder_error(format!(
217                "Cell must contain at most 4 references, got {}",
218                ref_count
219            )));
220        }
221        self.references.push(cell.clone());
222        Ok(self)
223    }
224
225    pub fn store_references(&mut self, refs: &[ArcCell]) -> Result<&mut Self, TonCellError> {
226        for r in refs {
227            self.store_reference(r)?;
228        }
229        Ok(self)
230    }
231
232    /// Adds a reference to a newly constructed `Cell`.
233    ///
234    /// The cell is wrapped it the `Arc`.
235    pub fn store_child(&mut self, cell: Cell) -> Result<&mut Self, TonCellError> {
236        self.store_reference(&Arc::new(cell))
237    }
238
239    pub fn store_remaining_bits(
240        &mut self,
241        parser: &mut CellParser,
242    ) -> Result<&mut Self, TonCellError> {
243        let num_full_bytes = parser.remaining_bits() / 8;
244        let bytes = parser.load_bytes(num_full_bytes)?;
245        self.store_slice(bytes.as_slice())?;
246        let num_bits = parser.remaining_bits() % 8;
247        let tail = parser.load_u8(num_bits)?;
248        self.store_u8(num_bits, tail)?;
249        Ok(self)
250    }
251
252    pub fn store_cell_data(&mut self, cell: &Cell) -> Result<&mut Self, TonCellError> {
253        let mut parser = cell.parser();
254        self.store_remaining_bits(&mut parser)?;
255        Ok(self)
256    }
257
258    pub fn store_cell(&mut self, cell: &Cell) -> Result<&mut Self, TonCellError> {
259        self.store_cell_data(cell)?;
260        self.store_references(cell.references.as_slice())?;
261        Ok(self)
262    }
263
264    // https://docs.ton.org/develop/data-formats/tl-b-types#either
265    pub fn store_either_cell_or_cell_ref(
266        &mut self,
267        cell: &ArcCell,
268        layout: EitherCellLayout,
269    ) -> Result<&mut Self, TonCellError> {
270        match layout {
271            EitherCellLayout::Native => {
272                if cell.bit_len() < self.remaining_bits() {
273                    self.store_bit(false)?;
274                    self.store_cell(cell)?;
275                } else {
276                    self.store_bit(true)?;
277                    self.store_reference(cell)?;
278                }
279            }
280            EitherCellLayout::ToRef => {
281                self.store_bit(true)?;
282                self.store_reference(cell)?;
283            }
284            EitherCellLayout::ToCell => {
285                self.store_bit(false)?;
286                self.store_cell(cell)?;
287            }
288        }
289
290        Ok(self)
291    }
292
293    // https://docs.ton.org/develop/data-formats/tl-b-types#maybe
294    pub fn store_maybe_cell_ref(
295        &mut self,
296        maybe_cell: &Option<ArcCell>,
297    ) -> Result<&mut Self, TonCellError> {
298        if let Some(cell) = maybe_cell {
299            self.store_bit(true)?;
300            self.store_reference(cell)?;
301        } else {
302            self.store_bit(false)?;
303        }
304
305        Ok(self)
306    }
307
308    pub fn store_dict<K, V>(
309        &mut self,
310        key_len_bits: usize,
311        value_writer: ValWriter<V>,
312        data: HashMap<K, V>,
313    ) -> Result<&mut Self, TonCellError>
314    where
315        BigUint: From<K>,
316    {
317        let dict_builder = DictBuilder::new(key_len_bits, value_writer, data)?;
318        let dict_cell = dict_builder.build()?;
319        self.store_cell(&dict_cell)
320    }
321
322    pub fn remaining_bits(&self) -> usize {
323        MAX_CELL_BITS - self.bits_to_write
324    }
325
326    pub fn build(&mut self) -> Result<Cell, TonCellError> {
327        let mut trailing_zeros = 0;
328        while !self.bit_writer.byte_aligned() {
329            self.bit_writer.write_bit(false).map_cell_builder_error()?;
330            trailing_zeros += 1;
331        }
332
333        if let Some(vec) = self.bit_writer.writer() {
334            let bit_len = vec.len() * 8 - trailing_zeros;
335            if bit_len > MAX_CELL_BITS {
336                return Err(TonCellError::cell_builder_error(format!(
337                    "Cell must contain at most {} bits, got {}",
338                    MAX_CELL_BITS, bit_len
339                )));
340            }
341            let ref_count = self.references.len();
342            if ref_count > MAX_CELL_REFERENCES {
343                return Err(TonCellError::cell_builder_error(format!(
344                    "Cell must contain at most 4 references, got {}",
345                    ref_count
346                )));
347            }
348
349            Cell::new(
350                vec.clone(),
351                bit_len,
352                self.references.clone(),
353                self.is_cell_exotic,
354            )
355        } else {
356            Err(TonCellError::CellBuilderError(
357                "Stream is not byte-aligned".to_string(),
358            ))
359        }
360    }
361}
362
363fn extend_and_invert_bits(bits_cnt: usize, src: &BigUint) -> Result<BigUint, TonCellError> {
364    if bits_cnt < src.bits() as usize {
365        return Err(TonCellError::cell_builder_error(format!(
366            "Can't invert bits: value {} doesn't fit in {} bits",
367            src, bits_cnt
368        )));
369    }
370
371    let src_bytes = src.to_bytes_be();
372    let inverted_bytes_cnt = (bits_cnt + 7) / 8;
373    let mut inverted = vec![0xffu8; inverted_bytes_cnt];
374    // can be optimized
375    for (pos, byte) in src_bytes.iter().rev().enumerate() {
376        let inverted_pos = inverted.len() - 1 - pos;
377        inverted[inverted_pos] ^= byte;
378    }
379    let mut inverted_val_bytes = BigUint::from_bytes_be(&inverted)
380        .add(BigUint::one())
381        .to_bytes_be();
382    let leading_zeros = inverted_bytes_cnt * 8 - bits_cnt;
383    inverted_val_bytes[0] &= 0xffu8 >> leading_zeros;
384    Ok(BigUint::from_bytes_be(&inverted_val_bytes))
385}
386
387impl Default for CellBuilder {
388    fn default() -> Self {
389        Self::new()
390    }
391}
392
393#[cfg(test)]
394mod tests {
395    use std::collections::HashMap;
396    use std::str::FromStr;
397
398    use num_bigint::{BigInt, BigUint, Sign};
399    use num_traits::Zero;
400
401    use crate::cell::builder::extend_and_invert_bits;
402    use crate::cell::dict::predefined_readers::{key_reader_u8, val_reader_uint};
403    use crate::cell::{CellBuilder, TonCellError};
404    use crate::types::TonAddress;
405
406    #[test]
407    fn test_extend_and_invert_bits() -> Result<(), TonCellError> {
408        let a = BigUint::from(1u8);
409        let b = extend_and_invert_bits(8, &a)?;
410        println!("a: {:0x}", a);
411        println!("b: {:0x}", b);
412        assert_eq!(b, BigUint::from(0xffu8));
413
414        let b = extend_and_invert_bits(16, &a)?;
415        assert_eq!(b, BigUint::from_slice(&[0xffffu32]));
416
417        let b = extend_and_invert_bits(20, &a)?;
418        assert_eq!(b, BigUint::from_slice(&[0xfffffu32]));
419
420        let b = extend_and_invert_bits(8, &a)?;
421        assert_eq!(b, BigUint::from_slice(&[0xffu32]));
422
423        let b = extend_and_invert_bits(9, &a)?;
424        assert_eq!(b, BigUint::from_slice(&[0x1ffu32]));
425
426        assert!(extend_and_invert_bits(3, &BigUint::from(10u32)).is_err());
427        Ok(())
428    }
429
430    #[test]
431    fn write_bit() -> Result<(), TonCellError> {
432        let mut writer = CellBuilder::new();
433        let cell = writer.store_bit(true)?.build()?;
434        assert_eq!(cell.data, [0b1000_0000]);
435        assert_eq!(cell.bit_len, 1);
436        let mut reader = cell.parser();
437        let result = reader.load_bit()?;
438        assert!(result);
439        Ok(())
440    }
441
442    #[test]
443    fn write_u8() -> Result<(), TonCellError> {
444        let value = 234u8;
445        let mut writer = CellBuilder::new();
446        let cell = writer.store_u8(8, value)?.build()?;
447        assert_eq!(cell.data, [0b1110_1010]);
448        assert_eq!(cell.bit_len, 8);
449        let mut reader = cell.parser();
450        let result = reader.load_u8(8)?;
451        assert_eq!(result, value);
452        Ok(())
453    }
454
455    #[test]
456    fn write_u32() -> Result<(), TonCellError> {
457        let value = 0xFAD45AADu32;
458        let mut writer = CellBuilder::new();
459        let cell = writer.store_u32(32, value)?.build()?;
460        assert_eq!(cell.data, [0xFA, 0xD4, 0x5A, 0xAD]);
461        assert_eq!(cell.bit_len, 32);
462        let mut reader = cell.parser();
463        let result = reader.load_u32(32)?;
464        assert_eq!(result, value);
465        Ok(())
466    }
467
468    #[test]
469    fn write_u64() -> Result<(), TonCellError> {
470        let value = 0xFAD45AADAA12FF45;
471        let mut writer = CellBuilder::new();
472        let cell = writer.store_u64(64, value)?.build()?;
473        assert_eq!(cell.data, [0xFA, 0xD4, 0x5A, 0xAD, 0xAA, 0x12, 0xFF, 0x45]);
474        assert_eq!(cell.bit_len, 64);
475        let mut reader = cell.parser();
476        let result = reader.load_u64(64)?;
477        assert_eq!(result, value);
478        Ok(())
479    }
480
481    #[test]
482    fn write_slice() -> Result<(), TonCellError> {
483        let value = [0xFA, 0xD4, 0x5A, 0xAD, 0xAA, 0x12, 0xFF, 0x45];
484        let mut writer = CellBuilder::new();
485        let cell = writer.store_slice(&value)?.build()?;
486        assert_eq!(cell.data, value);
487        assert_eq!(cell.bit_len, 64);
488        let mut reader = cell.parser();
489        let bytes = reader.load_bytes(8)?;
490        assert_eq!(bytes, value);
491        Ok(())
492    }
493
494    #[test]
495    fn write_str() -> Result<(), TonCellError> {
496        let texts = ["hello", "Русский текст", "中华人民共和国", "\u{263A}😃"];
497        for text in texts {
498            let mut writer = CellBuilder::new();
499            let cell = writer.store_string(text)?.build()?;
500            let text_bytes = text.as_bytes();
501            assert_eq!(cell.data, text_bytes);
502            assert_eq!(cell.bit_len, text_bytes.len() * 8);
503            let mut reader = cell.parser();
504            let remaining_bytes = reader.remaining_bytes();
505            let result = reader.load_utf8(remaining_bytes)?;
506            assert_eq!(result, text);
507        }
508        Ok(())
509    }
510
511    #[test]
512    fn write_address() -> Result<(), TonCellError> {
513        let addr = TonAddress::from_base64_url("EQDk2VTvn04SUKJrW7rXahzdF8_Qi6utb0wj43InCu9vdjrR")
514            .unwrap();
515
516        let mut writer = CellBuilder::new();
517        let cell = writer.store_address(&addr)?.build()?;
518        assert_eq!(
519            cell.data,
520            [
521                128, 28, 155, 42, 157, 243, 233, 194, 74, 20, 77, 107, 119, 90, 237, 67, 155, 162,
522                249, 250, 17, 117, 117, 173, 233, 132, 124, 110, 68, 225, 93, 237, 238, 192
523            ]
524        );
525        assert_eq!(cell.bit_len, 2 + 1 + 8 + 32 * 8);
526        let mut reader = cell.parser();
527        let result = reader.load_address()?;
528        assert_eq!(result, addr);
529        Ok(())
530    }
531
532    #[test]
533    fn write_big_int() -> Result<(), TonCellError> {
534        let value = BigInt::from_str("3").unwrap();
535        let mut writer = CellBuilder::new();
536        writer.store_int(33, &value)?;
537        let cell = writer.build()?;
538        println!("cell: {:?}", cell);
539        let written = BigInt::from_bytes_be(Sign::Plus, &cell.data);
540        assert_eq!(written, value);
541
542        // 256 bits (+ sign)
543        let value = BigInt::from_str(
544            "97887266651548624282413032824435501549503168134499591480902563623927645013201",
545        )
546        .unwrap();
547        let mut writer = CellBuilder::new();
548        writer.store_int(257, &value)?;
549        let cell = writer.build()?;
550        println!("cell: {:?}", cell);
551        let written = BigInt::from_bytes_be(Sign::Plus, &cell.data);
552        assert_eq!(written, value);
553
554        let value = BigInt::from_str("-5").unwrap();
555        let mut writer = CellBuilder::new();
556        writer.store_int(5, &value)?;
557        let cell = writer.build()?;
558        println!("cell: {:?}", cell);
559        let written = BigInt::from_bytes_be(Sign::Plus, &cell.data[1..]);
560        let expected = BigInt::from_bytes_be(Sign::Plus, &[0xB0u8]);
561        assert_eq!(written, expected);
562        Ok(())
563    }
564
565    #[test]
566    fn write_load_big_uint() -> Result<(), TonCellError> {
567        let value = BigUint::from_str("3").unwrap();
568        let mut writer = CellBuilder::new();
569        assert!(writer.store_uint(1, &value).is_err());
570        let bits_for_tests = [256, 128, 64, 8];
571
572        for bits_num in bits_for_tests.iter() {
573            writer.store_uint(*bits_num, &value)?;
574        }
575        let cell = writer.build()?;
576        println!("cell: {:?}", cell);
577        let mut cell_parser = cell.parser();
578        for bits_num in bits_for_tests.iter() {
579            let written_value = cell_parser.load_uint(*bits_num)?;
580            assert_eq!(written_value, value);
581        }
582
583        // 256 bit
584        let value = BigUint::from_str(
585            "97887266651548624282413032824435501549503168134499591480902563623927645013201",
586        )
587        .unwrap();
588        let mut writer = CellBuilder::new();
589        assert!(writer.store_uint(255, &value).is_err());
590        let bits_for_tests = [496, 264, 256];
591        for bits_num in bits_for_tests.iter() {
592            writer.store_uint(*bits_num, &value)?;
593        }
594        let cell = writer.build()?;
595        let mut cell_parser = cell.parser();
596        println!("cell: {:?}", cell);
597        for bits_num in bits_for_tests.iter() {
598            let written_value = cell_parser.load_uint(*bits_num)?;
599            assert_eq!(written_value, value);
600        }
601
602        Ok(())
603    }
604
605    #[test]
606    fn test_padding() -> Result<(), TonCellError> {
607        let mut writer = CellBuilder::new();
608
609        let n = BigUint::from(0x55a5f0f0u32);
610
611        writer.store_uint(32, &BigUint::zero())?;
612        writer.store_uint(32, &n)?;
613        writer.store_uint(31, &BigUint::zero())?;
614        writer.store_uint(31, &n)?;
615        writer.store_uint(35, &BigUint::zero())?;
616        writer.store_uint(35, &n)?;
617        let cell = writer.build()?;
618
619        println!("{:?}", cell);
620        assert_eq!(cell.data.len(), 25);
621        assert_eq!(cell.bit_len, 196);
622
623        let mut parser = cell.parser();
624        let result_zero = parser.load_uint(32)?;
625        let result_test_num = parser.load_uint(32)?;
626
627        assert_eq!(result_zero, BigUint::zero());
628        assert_eq!(result_test_num, n);
629        let result_zero = parser.load_uint(31)?;
630        let result_test_num = parser.load_uint(31)?;
631
632        assert_eq!(result_zero, BigUint::zero());
633        assert_eq!(result_test_num, n);
634        let result_zero = parser.load_uint(35)?;
635        let result_test_num = parser.load_uint(35)?;
636
637        assert_eq!(result_zero, BigUint::zero());
638
639        assert_eq!(result_test_num, n);
640        parser.ensure_empty()?;
641
642        Ok(())
643    }
644
645    #[test]
646    fn test_zero_alone() -> Result<(), TonCellError> {
647        let bitlens_to_test = [
648            1, 7, 8, 9, 30, 31, 32, 33, 127, 128, 129, 255, 256, 257, 300,
649        ];
650        for bitlen in bitlens_to_test {
651            let mut writer = CellBuilder::new();
652            writer.store_uint(bitlen, &BigUint::zero())?;
653
654            let cell = writer.build()?;
655
656            println!("{:?}", cell);
657            let taeget_bytelen = (bitlen + 7) / 8;
658            assert_eq!(cell.data.len(), taeget_bytelen);
659
660            assert_eq!(cell.bit_len, bitlen);
661
662            let mut parser = cell.parser();
663            let result_zero = parser.load_uint(bitlen)?;
664
665            assert_eq!(result_zero, BigUint::zero());
666            parser.ensure_empty()?;
667        }
668        Ok(())
669    }
670
671    #[test]
672    fn test_store_dict() -> Result<(), TonCellError> {
673        let mut builder = CellBuilder::new();
674        let mut data = HashMap::new();
675        data.insert(1u8, BigUint::from(2u8));
676        data.insert(3u8, BigUint::from(4u8));
677
678        let value_writer = |writer: &mut CellBuilder, value: BigUint| {
679            writer.store_uint(8, &value)?;
680            Ok(())
681        };
682        builder.store_dict(8, value_writer, data.clone())?;
683        let cell = builder.build()?;
684        let mut parser = cell.parser();
685        let parsed = parser.load_dict(8, key_reader_u8, val_reader_uint)?;
686        assert_eq!(data, parsed);
687        Ok(())
688    }
689}