tonlib_core/cell/
slice.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::io::Cursor;
use std::sync::Arc;

use bitstream_io::{BigEndian, BitRead, BitReader};

use crate::cell::util::BitReadExt;
use crate::cell::{ArcCell, Cell, MapTonCellError, TonCellError};

#[derive(Debug, Clone, PartialEq)]
pub struct CellSlice {
    pub cell: ArcCell,
    pub start_bit: usize,
    pub end_bit: usize,
    pub start_ref: usize,
    pub end_ref: usize,
}

impl CellSlice {
    pub fn new(
        cell: &ArcCell,
        start_bit: usize,
        end_bit: usize,
        start_ref: usize,
        end_ref: usize,
    ) -> Result<CellSlice, TonCellError> {
        if end_bit < start_bit || end_bit > cell.bit_len {
            return Err(TonCellError::CellParserError(format!(
                "Invalid bit offsets: start: {}, end: {}, bit_len: {}",
                start_bit, end_bit, cell.bit_len
            )));
        }
        if end_ref < start_ref || end_ref > cell.references.len() {
            return Err(TonCellError::CellParserError(format!(
                "Invalid references: start: {}, end: {}, count: {}",
                start_bit,
                end_bit,
                cell.references.len()
            )));
        }
        Ok(CellSlice {
            cell: cell.clone(),
            start_bit,
            end_bit,
            start_ref,
            end_ref,
        })
    }

    pub fn new_with_offset(cell: &Cell, offset: usize) -> Result<CellSlice, TonCellError> {
        CellSlice::new(
            &Arc::new(cell.clone()),
            offset,
            cell.bit_len,
            0,
            cell.references.len(),
        )
    }

    pub fn full_cell(cell: Cell) -> Result<CellSlice, TonCellError> {
        let bit_len = cell.bit_len;
        let ref_count = cell.references.len();
        Ok(CellSlice {
            cell: Arc::new(cell),
            start_bit: 0,
            end_bit: bit_len,
            start_ref: 0,
            end_ref: ref_count,
        })
    }

    pub fn reference(&self, idx: usize) -> Result<&ArcCell, TonCellError> {
        if idx > self.end_ref - self.start_ref {
            return Err(TonCellError::InvalidIndex {
                idx,
                ref_count: self.end_ref - self.start_ref,
            });
        }
        self.cell
            .references
            .get(self.start_ref + idx)
            .ok_or(TonCellError::InvalidIndex {
                idx,
                ref_count: self.end_ref - self.start_ref,
            })
    }

    /// Converts the slice to full `Cell` dropping references to original cell.
    pub fn into_cell(&self) -> Result<Cell, TonCellError> {
        let bit_len = self.end_bit - self.start_bit;
        let total_bytes = (bit_len + 7) / 8;
        let mut data = vec![0u8; total_bytes];
        let cursor = Cursor::new(&self.cell.data);
        let mut bit_reader: BitReader<Cursor<&Vec<u8>>, BigEndian> =
            BitReader::endian(cursor, BigEndian);
        bit_reader
            .skip(self.start_bit as u32)
            .map_cell_parser_error()?;
        bit_reader.read_bits(bit_len, data.as_mut_slice())?;

        Cell::new(
            data,
            bit_len,
            self.cell.references[self.start_ref..self.end_ref].to_vec(),
            false,
        )
    }
}