1use crate::{NeoArray, NeoString, NeoValue};
33
34pub const MAX_NOTIFICATION_SIZE: usize = 1024;
36
37pub const MAX_STACK_SIZE: usize = 1024;
39
40const TAG_NULL: u8 = 0x00;
42const TAG_BOOLEAN: u8 = 0x20;
43const TAG_INTEGER: u8 = 0x21;
44const TAG_BYTESTRING: u8 = 0x28;
45const TAG_ARRAY: u8 = 0x40;
46const TAG_STRUCT: u8 = 0x41;
47
48fn push_varint(out: &mut Vec<u8>, value: usize) {
60 let value = value as u64;
61 if value < 0xFD {
62 out.push(value as u8);
63 } else if value <= u16::MAX as u64 {
64 out.push(0xFD);
65 out.extend_from_slice(&(value as u16).to_le_bytes());
66 } else if value <= u32::MAX as u64 {
67 out.push(0xFE);
68 out.extend_from_slice(&(value as u32).to_le_bytes());
69 } else {
70 out.push(0xFF);
71 out.extend_from_slice(&value.to_le_bytes());
72 }
73}
74
75fn push_integer(out: &mut Vec<u8>, n: &crate::NeoInteger) {
76 let bigint = n.as_bigint();
77 out.push(TAG_INTEGER);
78 if bigint.sign() == num_bigint::Sign::NoSign {
83 push_varint(out, 0);
84 return;
85 }
86 let bytes = bigint.to_signed_bytes_le();
87 push_varint(out, bytes.len());
88 out.extend_from_slice(&bytes);
89}
90
91fn push_bytestring(out: &mut Vec<u8>, bytes: &[u8]) {
92 out.push(TAG_BYTESTRING);
93 push_varint(out, bytes.len());
94 out.extend_from_slice(bytes);
95}
96
97fn push_boolean(out: &mut Vec<u8>, b: bool) {
98 out.push(TAG_BOOLEAN);
99 out.push(if b { 0x01 } else { 0x00 });
100}
101
102fn push_stack_item(out: &mut Vec<u8>, value: &NeoValue) {
103 match value {
104 NeoValue::Null => out.push(TAG_NULL),
105 NeoValue::Boolean(b) => push_boolean(out, b.as_bool()),
106 NeoValue::Integer(i) => push_integer(out, i),
107 NeoValue::ByteString(bs) => push_bytestring(out, bs.as_slice()),
108 NeoValue::String(s) => push_bytestring(out, s.as_str().as_bytes()),
109 NeoValue::Array(arr) => {
110 out.push(TAG_ARRAY);
111 push_varint(out, arr.len());
112 for item in arr.iter() {
113 push_stack_item(out, item);
114 }
115 }
116 NeoValue::Struct(items) => {
117 out.push(TAG_STRUCT);
123 push_varint(out, items.len());
124 for (_name, value) in items.iter() {
125 push_stack_item(out, value);
126 }
127 }
128 NeoValue::Map(_) => {
129 out.push(TAG_NULL);
133 }
134 }
135}
136
137pub fn serialise_array(items: &NeoArray<NeoValue>) -> Vec<u8> {
143 let mut out = Vec::with_capacity(items.len() * 4 + 2);
144 out.push(TAG_ARRAY);
145 push_varint(&mut out, items.len());
146 for item in items.iter() {
147 push_stack_item(&mut out, item);
148 }
149 out
150}
151
152pub fn serialise_value(value: &NeoValue) -> Vec<u8> {
155 let mut out = Vec::with_capacity(8);
156 push_stack_item(&mut out, value);
157 out
158}
159
160pub fn serialise_notification(event: &NeoString, state: &NeoArray<NeoValue>) -> Vec<u8> {
164 let mut out = Vec::with_capacity(event.as_str().len() + state.len() * 4 + 4);
165 out.push(TAG_ARRAY);
167 push_varint(&mut out, 2);
168 push_bytestring(&mut out, event.as_str().as_bytes());
169 push_stack_item(&mut out, &NeoValue::Array(state.clone()));
170 out
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use crate::{NeoBoolean, NeoByteString, NeoInteger};
177
178 #[test]
179 fn varint_single_byte() {
180 let mut out = Vec::new();
183 push_varint(&mut out, 0);
184 push_varint(&mut out, 127);
185 push_varint(&mut out, 128);
186 push_varint(&mut out, 252);
187 assert_eq!(out, vec![0, 127, 128, 252]);
188 }
189
190 #[test]
191 fn varint_0xfd_marker() {
192 let mut out = Vec::new();
194 push_varint(&mut out, 253);
195 assert_eq!(out, vec![0xFD, 0xFD, 0x00]);
196
197 let mut out = Vec::new();
198 push_varint(&mut out, 0x1234);
199 assert_eq!(out, vec![0xFD, 0x34, 0x12]);
200 }
201
202 #[test]
203 fn varint_0xfe_marker() {
204 let mut out = Vec::new();
206 push_varint(&mut out, 0x0001_0000);
207 assert_eq!(out, vec![0xFE, 0x00, 0x00, 0x01, 0x00]);
208 }
209
210 #[test]
211 fn bytestring_length_128_uses_single_byte_prefix() {
212 let payload = vec![0xABu8; 128];
215 let bytes = serialise_value(&NeoValue::ByteString(crate::NeoByteString::from_slice(
216 &payload,
217 )));
218 assert_eq!(bytes[0], TAG_BYTESTRING);
219 assert_eq!(bytes[1], 0x80); assert_eq!(&bytes[2..], &payload[..]);
221 assert_eq!(bytes.len(), 130);
222 }
223
224 #[test]
225 fn tag_values_match_neo_stack_item_type() {
226 assert_eq!(TAG_NULL, 0x00);
229 assert_eq!(TAG_BOOLEAN, 0x20);
230 assert_eq!(TAG_INTEGER, 0x21);
231 assert_eq!(TAG_BYTESTRING, 0x28);
232 assert_eq!(TAG_ARRAY, 0x40);
233 assert_eq!(TAG_STRUCT, 0x41);
234 }
235
236 #[test]
237 fn integer_positive() {
238 let n = NeoInteger::new(42i32);
239 let mut out = Vec::new();
240 push_integer(&mut out, &n);
241 assert_eq!(out, vec![0x21, 0x01, 0x2A]);
243 }
244
245 #[test]
246 fn integer_zero_is_empty() {
247 let mut out = Vec::new();
249 push_integer(&mut out, &NeoInteger::new(0i32));
250 assert_eq!(out, vec![0x21, 0x00]);
251 }
252
253 #[test]
254 fn integer_multibyte_is_little_endian() {
255 let mut out = Vec::new();
259 push_integer(&mut out, &NeoInteger::new(1000i32));
260 assert_eq!(out, vec![0x21, 0x02, 0xE8, 0x03]);
261
262 let mut out = Vec::new();
264 push_integer(&mut out, &NeoInteger::new(128i32));
265 assert_eq!(out, vec![0x21, 0x02, 0x80, 0x00]);
266 }
267
268 #[test]
269 fn integer_negative_minimum_length() {
270 let n = NeoInteger::new(-1i32);
272 let mut out = Vec::new();
273 push_integer(&mut out, &n);
274 assert_eq!(out, vec![0x21, 0x01, 0xFF]);
275
276 let mut out = Vec::new();
278 push_integer(&mut out, &NeoInteger::new(-256i32));
279 assert_eq!(out, vec![0x21, 0x02, 0x00, 0xFF]);
280 }
281
282 #[test]
283 fn boolean() {
284 let mut out = Vec::new();
285 push_boolean(&mut out, true);
286 assert_eq!(out, vec![0x20, 0x01]);
287 push_boolean(&mut out, false);
288 assert_eq!(out, vec![0x20, 0x01, 0x20, 0x00]);
289 }
290
291 #[test]
292 fn empty_array() {
293 let arr = NeoArray::<NeoValue>::new();
294 let bytes = serialise_array(&arr);
295 assert_eq!(bytes, vec![TAG_ARRAY, 0x00]);
296 }
297
298 #[test]
299 fn array_with_int_and_bool() {
300 let mut arr = NeoArray::new();
301 arr.push(NeoValue::Integer(NeoInteger::new(7i32)));
302 arr.push(NeoValue::Boolean(NeoBoolean::new(true)));
303 let bytes = serialise_array(&arr);
304 assert_eq!(
306 bytes,
307 vec![TAG_ARRAY, 0x02, TAG_INTEGER, 0x01, 0x07, TAG_BOOLEAN, 0x01]
308 );
309 }
310
311 #[test]
312 fn notification_event_plus_state() {
313 let mut arr = NeoArray::new();
314 arr.push(NeoValue::Integer(NeoInteger::new(99i32)));
315 let event = NeoString::from_str("Transfer");
316 let bytes = serialise_notification(&event, &arr);
317 let mut expected = vec![TAG_ARRAY, 0x02];
319 expected.push(TAG_BYTESTRING);
321 expected.push(8);
322 expected.extend_from_slice(b"Transfer");
323 expected.push(TAG_ARRAY);
325 expected.push(0x01);
326 expected.push(TAG_INTEGER);
327 expected.push(0x01);
328 expected.push(0x63);
329 assert_eq!(bytes, expected);
330 }
331
332 #[test]
333 fn bytestring_value() {
334 let v = NeoValue::ByteString(NeoByteString::from_slice(&[1, 2, 3]));
335 let bytes = serialise_value(&v);
336 assert_eq!(bytes, vec![TAG_BYTESTRING, 0x03, 0x01, 0x02, 0x03]);
337 }
338}