solana_bytes_reader/
lib.rs

1use solana_program_error::ProgramError;
2
3
4pub trait ReadBytes {
5    type Error;
6
7    /// # Safety
8    /// The caller is responsible for ensuring that the range `[start..start + 8]`
9    /// is within bounds of the `data` slice.
10    fn read_u64(&self, start: usize) -> Result<u64, Self::Error>;
11
12    /// # Safety
13    /// The caller is responsible for ensuring that the range `[start..start + 8]`
14    /// is within bounds of the `data` slice.
15    fn read_i64(&self, start: usize) -> Result<i64, Self::Error>;
16
17    /// # Safety
18    /// The caller is responsible for ensuring that the range `[start..start + 4]`
19    /// is within bounds of the `data` slice.
20    fn read_u32(&self, start: usize) -> Result<u32, Self::Error>;
21}
22
23/// It's recommended to initialize `Reader` and use it's methods if there are more than 2 method calls.
24/// 
25/// Otherwise there's no need in this struct and functions can be used instead.
26pub struct Reader<'a> {
27    pub bytes: &'a [u8]
28}
29
30impl<'a> From<&'a [u8]> for Reader<'a> {
31    fn from(bytes: &'a [u8]) -> Self {
32        Self { bytes }
33    }
34}
35
36impl ReadBytes for Reader<'_> {
37    type Error = ProgramError;
38
39    fn read_u64(&self, start: usize) -> Result<u64, Self::Error> {
40        read_u64_slice(self.bytes, start)
41    }
42
43    fn read_i64(&self, start: usize) -> Result<i64, Self::Error> {
44        read_i64_slice(self.bytes, start)
45    }
46
47    fn read_u32(&self, start: usize) -> Result<u32, Self::Error> {
48        read_u32_slice(self.bytes, start)
49    }
50}
51
52/// # Safety
53/// The caller is responsible for ensuring that the range `[start..start + 8]`
54/// is within bounds of the `data` slice.
55pub fn read_u64_slice(data: &[u8], start: usize) -> Result<u64, ProgramError> {
56    Ok(
57        u64::from_le_bytes(data[start..start + 8]
58            .try_into()
59            .map_err(|_| ProgramError::InvalidInstructionData)?
60        )
61    )
62}
63
64/// # Safety
65/// The caller is responsible for ensuring that the range `[start..start + 8]`
66/// is within bounds of the `data` slice.
67pub fn read_i64_slice(data: &[u8], start: usize) -> Result<i64, ProgramError> {
68    Ok(
69        i64::from_le_bytes(data[start..start + 8]
70            .try_into()
71            .map_err(|_| ProgramError::InvalidInstructionData)?
72        )
73    )
74}
75
76/// # Safety
77/// The caller is responsible for ensuring that the range `[start..start + 4]`
78/// is within bounds of the `data` slice.
79pub fn read_u32_slice(data: &[u8], start: usize) -> Result<u32, ProgramError> {
80    Ok(
81        u32::from_le_bytes(data[start..start + 4]
82            .try_into()
83            .map_err(|_| ProgramError::InvalidInstructionData)?
84        )
85    )
86}