tonlib_core/cell/
slice.rs

1use std::io::Cursor;
2use std::sync::Arc;
3
4use bitstream_io::{BigEndian, BitRead, BitReader};
5
6use crate::cell::util::BitReadExt;
7use crate::cell::{ArcCell, Cell, MapTonCellError, TonCellError};
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct CellSlice {
11    pub cell: ArcCell,
12    pub start_bit: usize,
13    pub end_bit: usize,
14    pub start_ref: usize,
15    pub end_ref: usize,
16}
17
18impl CellSlice {
19    pub fn new(
20        cell: &ArcCell,
21        start_bit: usize,
22        end_bit: usize,
23        start_ref: usize,
24        end_ref: usize,
25    ) -> Result<CellSlice, TonCellError> {
26        if end_bit < start_bit || end_bit > cell.bit_len {
27            return Err(TonCellError::CellParserError(format!(
28                "Invalid bit offsets: start: {}, end: {}, bit_len: {}",
29                start_bit, end_bit, cell.bit_len
30            )));
31        }
32        if end_ref < start_ref || end_ref > cell.references.len() {
33            return Err(TonCellError::CellParserError(format!(
34                "Invalid references: start: {}, end: {}, count: {}",
35                start_bit,
36                end_bit,
37                cell.references.len()
38            )));
39        }
40        Ok(CellSlice {
41            cell: cell.clone(),
42            start_bit,
43            end_bit,
44            start_ref,
45            end_ref,
46        })
47    }
48
49    pub fn new_with_offset(cell: &Cell, offset: usize) -> Result<CellSlice, TonCellError> {
50        CellSlice::new(
51            &Arc::new(cell.clone()),
52            offset,
53            cell.bit_len,
54            0,
55            cell.references.len(),
56        )
57    }
58
59    pub fn full_cell(cell: Cell) -> Result<CellSlice, TonCellError> {
60        let bit_len = cell.bit_len;
61        let ref_count = cell.references.len();
62        Ok(CellSlice {
63            cell: Arc::new(cell),
64            start_bit: 0,
65            end_bit: bit_len,
66            start_ref: 0,
67            end_ref: ref_count,
68        })
69    }
70
71    pub fn reference(&self, idx: usize) -> Result<&ArcCell, TonCellError> {
72        if idx > self.end_ref - self.start_ref {
73            return Err(TonCellError::InvalidIndex {
74                idx,
75                ref_count: self.end_ref - self.start_ref,
76            });
77        }
78        self.cell
79            .references
80            .get(self.start_ref + idx)
81            .ok_or(TonCellError::InvalidIndex {
82                idx,
83                ref_count: self.end_ref - self.start_ref,
84            })
85    }
86
87    /// Converts the slice to full `Cell` dropping references to original cell.
88    pub fn into_cell(&self) -> Result<Cell, TonCellError> {
89        let bit_len = self.end_bit - self.start_bit;
90        let total_bytes = bit_len.div_ceil(8);
91        let mut data = vec![0u8; total_bytes];
92        let cursor = Cursor::new(&self.cell.data);
93        let mut bit_reader: BitReader<Cursor<&Vec<u8>>, BigEndian> =
94            BitReader::endian(cursor, BigEndian);
95        bit_reader
96            .skip(self.start_bit as u32)
97            .map_cell_parser_error()?;
98        bit_reader.read_bits(bit_len, data.as_mut_slice())?;
99
100        Cell::new(
101            data,
102            bit_len,
103            self.cell.references[self.start_ref..self.end_ref].to_vec(),
104            false,
105        )
106    }
107}