miraland_program/serialize_utils/
cursor.rs

1use {
2    crate::{instruction::InstructionError, pubkey::Pubkey},
3    std::io::{Cursor, Read},
4};
5
6pub(crate) fn read_u8<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<u8, InstructionError> {
7    let mut buf = [0; 1];
8    cursor
9        .read_exact(&mut buf)
10        .map_err(|_| InstructionError::InvalidAccountData)?;
11
12    Ok(buf[0])
13}
14
15pub(crate) fn read_u32<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<u32, InstructionError> {
16    let mut buf = [0; 4];
17    cursor
18        .read_exact(&mut buf)
19        .map_err(|_| InstructionError::InvalidAccountData)?;
20
21    Ok(u32::from_le_bytes(buf))
22}
23
24pub(crate) fn read_u64<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<u64, InstructionError> {
25    let mut buf = [0; 8];
26    cursor
27        .read_exact(&mut buf)
28        .map_err(|_| InstructionError::InvalidAccountData)?;
29
30    Ok(u64::from_le_bytes(buf))
31}
32
33pub(crate) fn read_option_u64<T: AsRef<[u8]>>(
34    cursor: &mut Cursor<T>,
35) -> Result<Option<u64>, InstructionError> {
36    let variant = read_u8(cursor)?;
37    match variant {
38        0 => Ok(None),
39        1 => read_u64(cursor).map(Some),
40        _ => Err(InstructionError::InvalidAccountData),
41    }
42}
43
44pub(crate) fn read_i64<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<i64, InstructionError> {
45    let mut buf = [0; 8];
46    cursor
47        .read_exact(&mut buf)
48        .map_err(|_| InstructionError::InvalidAccountData)?;
49
50    Ok(i64::from_le_bytes(buf))
51}
52
53pub(crate) fn read_pubkey<T: AsRef<[u8]>>(
54    cursor: &mut Cursor<T>,
55) -> Result<Pubkey, InstructionError> {
56    let mut buf = [0; 32];
57    cursor
58        .read_exact(&mut buf)
59        .map_err(|_| InstructionError::InvalidAccountData)?;
60
61    Ok(Pubkey::from(buf))
62}
63
64pub(crate) fn read_bool<T: AsRef<[u8]>>(cursor: &mut Cursor<T>) -> Result<bool, InstructionError> {
65    let byte = read_u8(cursor)?;
66    match byte {
67        0 => Ok(false),
68        1 => Ok(true),
69        _ => Err(InstructionError::InvalidAccountData),
70    }
71}
72
73#[cfg(test)]
74mod test {
75    use {super::*, rand::Rng, std::fmt::Debug};
76
77    #[test]
78    fn test_read_u8() {
79        for _ in 0..100 {
80            let test_value = rand::random::<u8>();
81            test_read(read_u8, test_value);
82        }
83    }
84
85    #[test]
86    fn test_read_u32() {
87        for _ in 0..100 {
88            let test_value = rand::random::<u32>();
89            test_read(read_u32, test_value);
90        }
91    }
92
93    #[test]
94    fn test_read_u64() {
95        for _ in 0..100 {
96            let test_value = rand::random::<u64>();
97            test_read(read_u64, test_value);
98        }
99    }
100
101    #[test]
102    fn test_read_option_u64() {
103        for _ in 0..100 {
104            let test_value = rand::random::<Option<u64>>();
105            test_read(read_option_u64, test_value);
106        }
107    }
108
109    #[test]
110    fn test_read_i64() {
111        for _ in 0..100 {
112            let test_value = rand::random::<i64>();
113            test_read(read_i64, test_value);
114        }
115    }
116
117    #[test]
118    fn test_read_pubkey() {
119        for _ in 0..100 {
120            let mut buf = [0; 32];
121            rand::thread_rng().fill(&mut buf);
122            let test_value = Pubkey::from(buf);
123            test_read(read_pubkey, test_value);
124        }
125    }
126
127    #[test]
128    fn test_read_bool() {
129        test_read(read_bool, false);
130        test_read(read_bool, true);
131    }
132
133    fn test_read<T: Debug + PartialEq + serde::Serialize + borsh0_10::BorshSerialize>(
134        reader: fn(&mut Cursor<Vec<u8>>) -> Result<T, InstructionError>,
135        test_value: T,
136    ) {
137        let bincode_bytes = bincode::serialize(&test_value).unwrap();
138        let mut cursor = Cursor::new(bincode_bytes);
139        let bincode_read = reader(&mut cursor).unwrap();
140
141        let borsh_bytes = borsh0_10::to_vec(&test_value).unwrap();
142        let mut cursor = Cursor::new(borsh_bytes);
143        let borsh_read = reader(&mut cursor).unwrap();
144
145        assert_eq!(test_value, bincode_read);
146        assert_eq!(test_value, borsh_read);
147    }
148}