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