Skip to main content

solana_tx_parser/
binary_reader.rs

1//! Binary buffer reader for instruction data.
2
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum BinaryReaderError {
7    #[error("buffer overflow: tried to read {requested} bytes at offset {offset} in buffer of length {length}")]
8    Overflow {
9        requested: usize,
10        offset: usize,
11        length: usize,
12    },
13}
14
15pub struct BinaryReader<'a> {
16    data: &'a [u8],
17    offset: usize,
18}
19
20impl<'a> BinaryReader<'a> {
21    pub fn new(data: &'a [u8]) -> Self {
22        Self { data, offset: 0 }
23    }
24
25    fn check_bounds(&self, length: usize) -> Result<(), BinaryReaderError> {
26        if self.offset + length > self.data.len() {
27            return Err(BinaryReaderError::Overflow {
28                requested: length,
29                offset: self.offset,
30                length: self.data.len(),
31            });
32        }
33        Ok(())
34    }
35
36    pub fn read_fixed_array(&mut self, length: usize) -> Result<&'a [u8], BinaryReaderError> {
37        self.check_bounds(length)?;
38        let slice = &self.data[self.offset..self.offset + length];
39        self.offset += length;
40        Ok(slice)
41    }
42
43    pub fn read_u8(&mut self) -> Result<u8, BinaryReaderError> {
44        self.check_bounds(1)?;
45        let v = self.data[self.offset];
46        self.offset += 1;
47        Ok(v)
48    }
49
50    pub fn read_u16_le(&mut self) -> Result<u16, BinaryReaderError> {
51        self.check_bounds(2)?;
52        let v = u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().unwrap());
53        self.offset += 2;
54        Ok(v)
55    }
56
57    pub fn read_u64_le(&mut self) -> Result<u64, BinaryReaderError> {
58        self.check_bounds(8)?;
59        let v = u64::from_le_bytes(self.data[self.offset..self.offset + 8].try_into().unwrap());
60        self.offset += 8;
61        Ok(v)
62    }
63
64    pub fn read_i64_le(&mut self) -> Result<i64, BinaryReaderError> {
65        self.check_bounds(8)?;
66        let v = i64::from_le_bytes(self.data[self.offset..self.offset + 8].try_into().unwrap());
67        self.offset += 8;
68        Ok(v)
69    }
70
71    pub fn read_string_u32_len(&mut self) -> Result<String, BinaryReaderError> {
72        let len = self.read_u32_le()? as usize;
73        self.check_bounds(len)?;
74        let s = String::from_utf8_lossy(&self.data[self.offset..self.offset + len]).into_owned();
75        self.offset += len;
76        Ok(s)
77    }
78
79    pub fn read_pubkey(&mut self) -> Result<String, BinaryReaderError> {
80        let slice = self.read_fixed_array(32)?;
81        Ok(bs58::encode(slice).into_string())
82    }
83
84    pub fn remaining(&self) -> usize {
85        self.data.len().saturating_sub(self.offset)
86    }
87
88    pub fn offset(&self) -> usize {
89        self.offset
90    }
91}
92
93// u32 read for string length
94impl BinaryReader<'_> {
95    pub fn read_u32_le(&mut self) -> Result<u32, BinaryReaderError> {
96        self.check_bounds(4)?;
97        let v = u32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap());
98        self.offset += 4;
99        Ok(v)
100    }
101}