avalanche_types/packer/
mod.rs

1//! Low-level byte-packing utilities.
2pub mod ip;
3
4use std::{cell::Cell, u16};
5
6use crate::errors::{Error, Result};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8
9pub const MAX_STR_LEN: u16 = u16::MAX - 1;
10
11/// number of bytes per byte
12/// 8-bit unsigned integer, so the length is 1-byte
13pub const BYTE_LEN: usize = 1;
14pub const BYTE_SENTINEL: u8 = 0;
15
16/// number of bytes per short
17/// 16-bit unsigned integer, so the length is 2-byte
18pub const U16_LEN: usize = 2;
19pub const U16_SENTINEL: u16 = 0;
20
21/// number of bytes per int
22/// 32-bit unsigned integer, so the length is 4-byte
23pub const U32_LEN: usize = 4;
24pub const U32_SENTINEL: u32 = 0;
25
26/// number of bytes per long
27/// 64-bit unsigned integer, so the length is 8-byte
28pub const U64_LEN: usize = 8;
29pub const U64_SENTINEL: u64 = 0;
30
31/// number of bytes per bool
32pub const BOOL_LEN: usize = 1;
33pub const BOOL_SENTINEL: bool = false;
34
35/// Packer packs and unpacks the underlying bytes array.
36/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer>
37/// ref. <https://doc.rust-lang.org/1.7.0/book/mutability.html>
38/// ref. <https://doc.rust-lang.org/std/cell/struct.Cell.html>
39pub struct Packer {
40    /// largest allowed size of expanding the byte array
41    max_size: usize,
42    /// current byte array
43    bytes: Cell<BytesMut>,
44    /// If true, then the first 4-bytes in "take_bytes"
45    /// encodes the length of the message.
46    /// The returned bytes length will be 4-byte + message.
47    header: bool,
48    /// offset that is being written to in the byte array
49    offset: Cell<usize>,
50}
51
52impl Packer {
53    pub fn new(max_size: usize, initial_cap: usize) -> Self {
54        let bytes = Cell::new(BytesMut::with_capacity(initial_cap));
55        Self {
56            max_size,
57            bytes,
58            header: false,
59            offset: Cell::new(0),
60        }
61    }
62
63    /// Creates a new Packer with 32-bit message length header.
64    pub fn new_with_header(max_size: usize, initial_cap: usize) -> Self {
65        let mut b = BytesMut::with_capacity(initial_cap);
66        b.put_slice(&[0x00, 0x00, 0x00, 0x00]);
67        let bytes = Cell::new(b);
68        let offset = Cell::new(4);
69        Self {
70            max_size,
71            bytes,
72            header: true,
73            offset,
74        }
75    }
76
77    /// Create a new packer from the existing bytes.
78    /// Resets the offset to the end of the existing bytes.
79    pub fn load_bytes_for_pack(max_size: usize, b: &[u8]) -> Self {
80        Self {
81            max_size,
82            bytes: Cell::new(BytesMut::from(b)),
83            header: false,
84            offset: Cell::new(b.len()),
85        }
86    }
87
88    /// Create a new packer from the existing bytes.
89    /// Resets the offset to the beginning of the existing bytes.
90    pub fn load_bytes_for_unpack(max_size: usize, b: &[u8]) -> Self {
91        Self {
92            max_size,
93            bytes: Cell::new(BytesMut::from(b)),
94            header: false,
95            offset: Cell::new(0),
96        }
97    }
98
99    /// Returns the current bytes array as an immutable bytes array.
100    /// If the packer header is set to "true", the first 4-byte represents
101    /// the message length in the big-endian order. The returned bytes length
102    /// will be 4-byte + message.
103    ///
104    /// Be cautious! Once bytes are taken out, the "bytes" field is set to default (empty).
105    /// To continue to write to bytes, remember to put it back with "set_bytes"
106    /// because "bytes.take" leaves the field as "Default::default()".
107    /// TODO: make sure this does shallow copy!
108    pub fn take_bytes(&self) -> Bytes {
109        let mut b = self.bytes.take();
110        let n = b.len();
111        if self.header {
112            assert!(n >= 4);
113            let msg_length = (n - 4) as u32;
114
115            let header = msg_length.to_be_bytes();
116            assert!(header.len() == 4);
117            b[0] = header[0];
118            b[1] = header[1];
119            b[2] = header[2];
120            b[3] = header[3];
121        }
122        b.copy_to_bytes(n)
123    }
124
125    /// Sets the current bytes array as an immutable bytes array.
126    /// Useful to reuse packer after calling "take_bytes", which
127    /// makes the "bytes" field default (empty).
128    pub fn set_bytes(&self, b: &[u8]) {
129        self.bytes.set(BytesMut::from(b));
130    }
131
132    /// Updates the "offset" field.
133    fn set_offset(&self, offset: usize) {
134        self.offset.set(offset)
135    }
136
137    /// Returns the "offset" value.
138    pub fn get_offset(&self) -> usize {
139        // "usize" implements "Copy" so just use "get" on "Cell"
140        // ref. https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-1
141        self.offset.get()
142    }
143
144    /// Returns the current length of the bytes array.
145    pub fn bytes_len(&self) -> usize {
146        // "BytesMut" does not implement "Copy" so take/update/set it back
147        // ref. https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-1
148        let b = self.bytes.take();
149        let n = b.len();
150        self.bytes.set(b);
151        n
152    }
153
154    /// Returns the current capacity of the bytes array.
155    pub fn bytes_cap(&self) -> usize {
156        // "BytesMut" does not implement "Copy" so take/update/set it back
157        // ref. https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-1
158        let b = self.bytes.take();
159        let n = b.capacity();
160        self.bytes.set(b);
161        n
162    }
163
164    /// Truncates the bytes array while retaining the underlying capacity.
165    fn truncate_bytes_with_length(&self, len: usize) {
166        // "BytesMut" does not implement "Copy" so take/update/set it back
167        // remember to put it back -- "take" leaves the field as "Default::default()"
168        // ref. https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-1
169        let mut b = self.bytes.take();
170        b.truncate(len);
171        self.bytes.set(b);
172    }
173
174    /// Reserves the bytes array while retaining the underlying length.
175    fn reserve_bytes_with_length(&self, len: usize) {
176        // "BytesMut" does not implement "Copy" so take/update/set it back
177        // remember to put it back -- "take" leaves the field as "Default::default()"
178        // ref. https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-1
179        let mut b = self.bytes.take();
180        b.reserve(len);
181        self.bytes.set(b);
182    }
183
184    /// Ensures the remaining capacity of the bytes array
185    /// so it can write "n" bytes to the array.
186    /// ref. "avalanchego/utils/wrappers.Packer.Expand"
187    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.Expand>
188    pub fn expand(&self, n: usize) -> Result<()> {
189        // total number of bytes that must be remained in the bytes array
190        let needed_size = self.get_offset() + n;
191
192        // already has sufficient length
193        // thus no need to check max_size
194        if needed_size <= self.bytes_len() {
195            return Ok(());
196        }
197
198        // byte slice would cause it to grow too large (out of bounds)
199        if needed_size > self.max_size {
200            return Err(Error::Other {
201                message: format!(
202                    "needed_size {} exceeds max_size {}",
203                    needed_size, self.max_size
204                ),
205                retryable: false,
206            });
207        }
208
209        // has sufficient capacity to lengthen it without mem alloc
210        let bytes_cap = self.bytes_cap();
211        if needed_size <= bytes_cap {
212            self.truncate_bytes_with_length(needed_size);
213            return Ok(());
214        }
215
216        // "avalanchego/utils/wrappers.Packer.Expand" is different in that
217        // it uses "resize" to fill in the array with zero values.
218        // As long as we maintain the "offset", it does not change the underlying
219        // packing algorithm, thus compatible.
220        self.reserve_bytes_with_length(needed_size);
221        Ok(())
222    }
223
224    /// Returns an error if the packer has insufficient length for the input size.
225    /// ref. "avalanchego/utils/wrappers.Packer.CheckSpace"
226    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.CheckSpace>
227    fn check_remaining_unpack(&self, bytes_to_read: usize) -> Result<()> {
228        let needed_size = self.get_offset() + bytes_to_read;
229        let bytes_n = self.bytes_len();
230        if needed_size > bytes_n {
231            return Err(Error::Other {
232                message:  format!(
233                    "bad length to read; offset + bytes ({}) to read exceeds current total bytes size {}",
234                    needed_size,
235                    bytes_n
236                ), // ref. "errBadLength"
237                retryable: false,
238            });
239        };
240        Ok(())
241    }
242
243    /// Writes the "u8" value at the offset and increments the offset afterwards.
244    /// ref. "avalanchego/utils/wrappers.Packer.PackByte"
245    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackByte>
246    pub fn pack_byte(&self, v: u8) -> Result<()> {
247        self.expand(BYTE_LEN)?;
248
249        let offset = self.get_offset();
250        let mut b = self.bytes.take();
251
252        // assume "offset" is not updated by the other "unpack*"
253        // thus no need to keep internal cursor in sync with "offset"
254        // unsafe { b.advance_mut(offset) };
255
256        // writes an unsigned 8-bit integer
257        b.put_u8(v);
258
259        // remember to put it back -- "take" leaves the field as "Default::default()"
260        self.bytes.set(b);
261
262        // "put_u8" already advances the current position by BYTE_LEN
263        // thus no need for "unsafe { b.advance_mut(offset + BYTE_LEN) };"
264        // ref. https://docs.rs/bytes/latest/bytes/buf/trait.BufMut.html#method.put_u8
265        self.set_offset(offset + BYTE_LEN);
266        Ok(())
267    }
268
269    /// Unpacks the byte in the "offset" position,
270    /// and advances the cursor and offset.
271    /// ref. "avalanchego/utils/wrappers.Packer.UnpackByte"
272    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackByte>
273    pub fn unpack_byte(&self) -> Result<u8> {
274        self.check_remaining_unpack(BYTE_LEN)?;
275
276        let offset = self.get_offset();
277        let b = self.bytes.take();
278
279        let p = &b[offset];
280        let v = *p;
281
282        // remember to put it back -- "take" leaves the field as "Default::default()"
283        self.bytes.set(b);
284
285        self.set_offset(offset + BYTE_LEN);
286        Ok(v)
287    }
288
289    /// Writes the "u16" value at the offset and increments the offset afterwards.
290    /// ref. "avalanchego/utils/wrappers.Packer.PackShort"
291    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackShort>
292    pub fn pack_u16(&self, v: u16) -> Result<()> {
293        self.expand(U16_LEN)?;
294
295        let offset = self.get_offset();
296        let mut b = self.bytes.take();
297
298        // assume "offset" is not updated by the other "unpack*"
299        // thus no need to keep internal cursor in sync with "offset"
300        // unsafe { b.advance_mut(offset) };
301
302        // writes an unsigned 16 bit integer in big-endian byte order
303        // ref. "binary.BigEndian.PutUint16"
304        b.put_u16(v);
305
306        // remember to put it back -- "take" leaves the field as "Default::default()"
307        self.bytes.set(b);
308
309        // "put_u16" already advances the current position by U16_LEN
310        // thus no need for "unsafe { b.advance_mut(offset + U16_LEN) };"
311        // ref. https://docs.rs/bytes/latest/bytes/buf/trait.BufMut.html#method.put_u16
312        self.set_offset(offset + U16_LEN);
313        Ok(())
314    }
315
316    /// Unpacks the u16 from the "offset" position,
317    /// and advances the cursor and offset.
318    /// ref. "avalanchego/utils/wrappers.Packer.UnpackShort"
319    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackShort>
320    pub fn unpack_u16(&self) -> Result<u16> {
321        self.check_remaining_unpack(U16_LEN)?;
322
323        let offset = self.get_offset();
324        let b = self.bytes.take();
325
326        let pos = &b[offset..offset + U16_LEN];
327
328        // ref. "binary.BigEndian.Uint16"
329        // ref. https://doc.rust-lang.org/std/primitive.u16.html#method.from_be_bytes
330        let v = u16::from_be_bytes([pos[0], pos[1]]);
331
332        // remember to put it back -- "take" leaves the field as "Default::default()"
333        self.bytes.set(b);
334
335        self.set_offset(offset + U16_LEN);
336        Ok(v)
337    }
338
339    /// Writes the "u32" value at the offset and increments the offset afterwards.
340    /// This is also used for encoding the type IDs from codec.
341    /// ref. "avalanchego/utils/wrappers.Packer.PackInt"
342    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackInt>
343    pub fn pack_u32(&self, v: u32) -> Result<()> {
344        self.expand(U32_LEN)?;
345
346        let offset = self.get_offset();
347        let mut b = self.bytes.take();
348
349        // assume "offset" is not updated by the other "unpack*"
350        // thus no need to keep internal cursor in sync with "offset"
351        // unsafe { b.advance_mut(offset) };
352
353        // writes an unsigned 32 bit integer in big-endian byte order
354        // ref. "binary.BigEndian.PutUint32"
355        b.put_u32(v);
356
357        // remember to put it back -- "take" leaves the field as "Default::default()"
358        self.bytes.set(b);
359
360        // "put_u32" already advances the current position by U32_LEN
361        // thus no need for "unsafe { b.advance_mut(offset + U32_LEN) };"
362        // ref. https://docs.rs/bytes/latest/bytes/buf/trait.BufMut.html#method.put_u32
363        self.set_offset(offset + U32_LEN);
364        Ok(())
365    }
366
367    /// Unpacks the u32 from the "offset" position,
368    /// and advances the cursor and offset.
369    /// ref. "avalanchego/utils/wrappers.Packer.UnpackInt"
370    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackInt>
371    pub fn unpack_u32(&self) -> Result<u32> {
372        self.check_remaining_unpack(U32_LEN)?;
373
374        let offset = self.get_offset();
375        let b = self.bytes.take();
376
377        let pos = &b[offset..offset + U32_LEN];
378
379        // ref. "binary.BigEndian.Uint32"
380        // ref. https://doc.rust-lang.org/std/primitive.u32.html#method.from_be_bytes
381        let v = u32::from_be_bytes([pos[0], pos[1], pos[2], pos[3]]);
382
383        // remember to put it back -- "take" leaves the field as "Default::default()"
384        self.bytes.set(b);
385
386        self.set_offset(offset + U32_LEN);
387        Ok(v)
388    }
389
390    /// Writes the "u64" value at the offset and increments the offset afterwards.
391    /// ref. "avalanchego/utils/wrappers.Packer.PackLong"
392    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackLong>
393    pub fn pack_u64(&self, v: u64) -> Result<()> {
394        self.expand(U64_LEN)?;
395
396        let offset = self.get_offset();
397        let mut b = self.bytes.take();
398
399        // assume "offset" is not updated by the other "unpack*"
400        // thus no need to keep internal cursor in sync with "offset"
401        // unsafe { b.advance_mut(offset) };
402
403        // writes an unsigned 64 bit integer in big-endian byte order
404        // ref. "binary.BigEndian.PutUint64"
405        b.put_u64(v);
406
407        // remember to put it back -- "take" leaves the field as "Default::default()"
408        self.bytes.set(b);
409
410        // "put_u64" already advances the current position by U64_LEN
411        // thus no need for "unsafe { b.advance_mut(offset + U64_LEN) };"
412        // ref. https://docs.rs/bytes/latest/bytes/buf/trait.BufMut.html#method.put_u64
413        self.set_offset(offset + U64_LEN);
414        Ok(())
415    }
416
417    /// Unpacks the u64 from the "offset" position,
418    /// and advances the cursor and offset.
419    /// ref. "avalanchego/utils/wrappers.Packer.UnpackLong"
420    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackLong>
421    pub fn unpack_u64(&self) -> Result<u64> {
422        self.check_remaining_unpack(U64_LEN)?;
423
424        let offset = self.get_offset();
425        let b = self.bytes.take();
426
427        let pos = &b[offset..offset + U64_LEN];
428
429        // ref. "binary.BigEndian.Uint64"
430        // ref. https://doc.rust-lang.org/std/primitive.u64.html#method.from_be_bytes
431        let v = u64::from_be_bytes([
432            pos[0], pos[1], pos[2], pos[3], pos[4], pos[5], pos[6], pos[7],
433        ]);
434
435        // remember to put it back -- "take" leaves the field as "Default::default()"
436        self.bytes.set(b);
437
438        self.set_offset(offset + U64_LEN);
439        Ok(v)
440    }
441
442    /// Writes the "bool" value at the offset and increments the offset afterwards.
443    /// ref. "avalanchego/utils/wrappers.Packer.PackBool"
444    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackBool>
445    pub fn pack_bool(&self, v: bool) -> Result<()> {
446        if v {
447            self.pack_byte(1)
448        } else {
449            self.pack_byte(0)
450        }
451    }
452
453    /// Unpacks the bool in the "offset" position,
454    /// and advances the cursor and offset.
455    /// ref. "avalanchego/utils/wrappers.Packer.UnpackBool"
456    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackBool>
457    pub fn unpack_bool(&self) -> Result<bool> {
458        let b = self.unpack_byte()?;
459        match b {
460            0 => Ok(false),
461            1 => Ok(true),
462            _ => {
463                Err(Error::Other {
464                    message: "unexpected value when unpacking bool".to_string(), // ref. "errBadBool"
465                    retryable: false,
466                })
467            }
468        }
469    }
470
471    /// Writes the "u8" fixed-size array from the offset and increments the offset as much.
472    /// ref. "avalanchego/utils/wrappers.Packer.PackFixedBytes"
473    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackFixedBytes>
474    pub fn pack_bytes(&self, v: &[u8]) -> Result<()> {
475        let n = v.len();
476        self.expand(n)?;
477
478        let offset = self.get_offset();
479        let mut b = self.bytes.take();
480
481        // assume "offset" is not updated by the other "unpack*"
482        // thus no need to keep internal cursor in sync with "offset"
483        // unsafe { b.advance_mut(offset) };
484
485        // writes bytes from the offset
486        // ref. "copy(p.Bytes[p.Offset:], bytes)"
487        b.put_slice(v);
488
489        // remember to put it back -- "take" leaves the field as "Default::default()"
490        self.bytes.set(b);
491
492        // "put_slice" already advances the current position by "n"
493        // thus no need for "unsafe { b.advance_mut(offset + n) };"
494        // ref. https://docs.rs/bytes/latest/bytes/buf/trait.BufMut.html#method.put_u64
495        self.set_offset(offset + n);
496        Ok(())
497    }
498
499    /// Unpacks the "u8" fixed-size array from the "offset" position,
500    /// and advances the cursor and offset.
501    /// ref. "avalanchego/utils/wrappers.Packer.UnpackFixedBytes"
502    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackFixedBytes>
503    pub fn unpack_bytes(&self, n: usize) -> Result<Vec<u8>> {
504        self.check_remaining_unpack(n)?;
505
506        let offset = self.get_offset();
507        let b = self.bytes.take();
508
509        let pos = &b[offset..offset + n];
510        let v = Vec::from(pos);
511
512        // remember to put it back -- "take" leaves the field as "Default::default()"
513        self.bytes.set(b);
514
515        self.set_offset(offset + n);
516        Ok(v)
517    }
518
519    /// Writes the "u8" slice from the offset and increments the offset as much.
520    /// The first 4-byte is used for encoding length header.
521    /// ref. "avalanchego/utils/wrappers.Packer.PackBytes"
522    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackBytes>
523    pub fn pack_bytes_with_header(&self, v: &[u8]) -> Result<()> {
524        self.pack_u32(v.len() as u32)?;
525        self.pack_bytes(v)
526    }
527
528    /// Unpacks the "u8" slice from the "offset" position,
529    /// and advances the cursor and offset.
530    /// ref. "avalanchego/utils/wrappers.Packer.UnpackBytes"
531    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackBytes>
532    pub fn unpack_bytes_with_header(&self) -> Result<Vec<u8>> {
533        let n = self.unpack_u32()?;
534        self.unpack_bytes(n as usize)
535    }
536
537    /// Writes the two-dimensional "u8" slice from the offset and increments the offset as much.
538    /// ref. "avalanchego/utils/wrappers.Packer.PackFixedByteSlices"
539    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackFixedByteSlices>
540    pub fn pack_2d_bytes(&self, v: Vec<Vec<u8>>) -> Result<()> {
541        self.pack_u32(v.len() as u32)?;
542        for vv in v.iter() {
543            self.pack_bytes(vv)?;
544        }
545        Ok(())
546    }
547
548    /// Unpacks the two-dimensional "u8" slice from the "offset" position,
549    /// and advances the cursor and offset.
550    /// ref. "avalanchego/utils/wrappers.Packer.UnpackFixedByteSlices"
551    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackFixedByteSlices>
552    pub fn unpack_2d_bytes(&self, n: usize) -> Result<Vec<Vec<u8>>> {
553        let total = self.unpack_u32()?;
554        let mut rs: Vec<Vec<u8>> = Vec::new();
555        for _ in 0..total {
556            let b = self.unpack_bytes(n)?;
557            rs.push(b);
558        }
559        Ok(rs)
560    }
561
562    /// Writes the two-dimensional "u8" slice from the offset and increments the offset as much.
563    /// ref. "avalanchego/utils/wrappers.Packer.Pack2DByteSlice"
564    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.Pack2DByteSlice>
565    pub fn pack_2d_bytes_with_header(&self, v: Vec<Vec<u8>>) -> Result<()> {
566        self.pack_u32(v.len() as u32)?;
567        for vv in v.iter() {
568            self.pack_bytes_with_header(vv)?;
569        }
570        Ok(())
571    }
572
573    /// Unpacks the two-dimensional "u8" slice from the "offset" position,
574    /// and advances the cursor and offset.
575    /// ref. "avalanchego/utils/wrappers.Packer.Unpack2DByteSlice"
576    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.Unpack2DByteSlice>
577    pub fn unpack_2d_bytes_with_header(&self) -> Result<Vec<Vec<u8>>> {
578        let total = self.unpack_u32()?;
579        let mut rs: Vec<Vec<u8>> = Vec::new();
580        for _ in 0..total {
581            let b = self.unpack_bytes_with_header()?;
582            rs.push(b);
583        }
584        Ok(rs)
585    }
586
587    /// Writes str from the offset and increments the offset as much.
588    /// ref. "avalanchego/utils/wrappers.Packer.PackStr"
589    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.PackStr>
590    pub fn pack_str(&self, v: &str) -> Result<()> {
591        let n = v.len() as u16;
592        if n > MAX_STR_LEN {
593            return Err(Error::Other {
594                message: format!("str {} > max_size {}", n, MAX_STR_LEN),
595                retryable: false,
596            });
597        }
598        self.pack_u16(n)?;
599        self.pack_bytes(v.as_bytes())
600    }
601
602    /// Unpacks str from the offset.
603    /// ref. "avalanchego/utils/wrappers.Packer.UnpackStr"
604    ///
605    /// TODO: Go "UnpackStr" does deep-copy of bytes to "string" cast
606    /// Can we bypass deep-copy by passing around bytes?
607    /// ref. <https://github.com/golang/go/issues/25484>
608    ///
609    /// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/wrappers#Packer.UnpackStr>
610    pub fn unpack_str(&self) -> Result<String> {
611        let n = self.unpack_u16()?;
612        let d = self.unpack_bytes(n as usize)?;
613        let s = match String::from_utf8(d) {
614            Ok(v) => v,
615            Err(e) => {
616                return Err(Error::Other {
617                    message: format!("failed String::from_utf8 {}", e),
618                    retryable: false,
619                });
620            }
621        };
622        Ok(s)
623    }
624}
625
626/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_expand --exact --show-output
627/// ref. "avalanchego/utils/wrappers.TestPackerExpand"
628#[test]
629fn test_expand() {
630    let s = [0x01];
631    let b = BytesMut::from(&s[..]);
632    let packer = Packer {
633        max_size: 0,
634        bytes: Cell::new(b),
635        header: false,
636        offset: Cell::new(2),
637    };
638    assert!(packer.expand(1).is_err());
639
640    let s = [0x01, 0x02, 0x03];
641    let b = BytesMut::from(&s[..]);
642    let packer = Packer {
643        max_size: 0,
644        bytes: Cell::new(b),
645        header: false,
646        offset: Cell::new(0),
647    };
648    packer.expand(1).unwrap();
649    assert_eq!(packer.bytes_len(), 3);
650
651    // 256 KiB
652    let packer = Packer::new(256 * 1024, 128);
653    packer.expand(10000).unwrap();
654    assert_eq!(packer.bytes_len(), 0);
655    assert_eq!(packer.bytes_cap(), 10000);
656}
657
658/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_packer_from_bytes --exact --show-output
659#[test]
660fn test_packer_from_bytes() {
661    let s: Vec<u8> = vec![0x01, 0x02, 0x03];
662    let packer = Packer::load_bytes_for_pack(10000, &s);
663    packer.pack_byte(0x10).unwrap();
664    assert_eq!(packer.bytes_len(), 4);
665    assert_eq!(packer.get_offset(), 4);
666
667    let b = packer.take_bytes();
668    assert_eq!(&b[..], b"\x01\x02\x03\x10");
669    let expected = [0x01, 0x02, 0x03, 0x10];
670    assert_eq!(&b[..], &expected[..]);
671}
672
673/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_byte --exact --show-output
674/// ref. "avalanchego/utils/wrappers.TestPackerPackByte"
675#[test]
676fn test_pack_byte() {
677    let packer = Packer::new(1, 0);
678    packer.pack_byte(0x01).unwrap();
679    assert_eq!(packer.bytes_len(), 1);
680    assert_eq!(packer.get_offset(), 1);
681
682    assert!(packer.pack_byte(0x02).is_err());
683    assert_eq!(packer.bytes_len(), 1);
684    assert_eq!(packer.get_offset(), 1);
685
686    let b = packer.take_bytes();
687    assert_eq!(&b[..], b"\x01");
688    let expected = [0x01];
689    assert_eq!(&b[..], &expected[..]);
690    assert_eq!(packer.bytes_len(), 0);
691    assert_eq!(packer.get_offset(), 1);
692
693    packer.set_bytes(&b);
694    assert_eq!(packer.bytes_len(), 1);
695
696    let packer = Packer::new_with_header(5, 0);
697    packer.pack_byte(0x01).unwrap();
698    let expected = [0x00, 0x00, 0x00, 0x01, 0x01];
699    assert_eq!(&packer.take_bytes()[..], &expected[..]);
700}
701
702/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_byte --exact --show-output
703/// ref. "avalanchego/utils/wrappers.TestPackerUnpackByte"
704#[test]
705fn test_unpack_byte() {
706    let s = [0x01];
707    let b = BytesMut::from(&s[..]);
708    let packer = Packer {
709        max_size: 0,
710        bytes: Cell::new(b),
711        header: false,
712        offset: Cell::new(0),
713    };
714    let b = packer.unpack_byte().unwrap();
715    assert_eq!(b, 1);
716    assert_eq!(packer.get_offset(), 1);
717
718    assert!(packer.unpack_byte().is_err());
719}
720
721/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_u16 --exact --show-output
722/// ref. "avalanchego/utils/wrappers.TestPackerPackShort"
723#[test]
724fn test_pack_u16() {
725    let packer = Packer {
726        max_size: U16_LEN,
727        bytes: Cell::new(BytesMut::with_capacity(0)),
728        header: false,
729        offset: Cell::new(0),
730    };
731    packer.pack_u16(0x0102).unwrap();
732    assert_eq!(packer.bytes_len(), U16_LEN);
733
734    let b = packer.take_bytes();
735    assert_eq!(&b[..], b"\x01\x02");
736    let expected = [0x01, 0x02];
737    assert_eq!(&b[..], &expected[..]);
738
739    let packer = Packer::new_with_header(4 + U16_LEN, 0);
740    packer.pack_u16(0x0102).unwrap();
741    let expected = [0x00, 0x00, 0x00, 0x02, 0x01, 0x02];
742    assert_eq!(&packer.take_bytes()[..], &expected[..]);
743}
744
745/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_u16 --exact --show-output
746/// ref. "avalanchego/utils/wrappers.TestPackerUnpackShort"
747#[test]
748fn test_unpack_u16() {
749    let s: Vec<u8> = vec![0x01, 0x02];
750    let b = BytesMut::from(&s[..]);
751    let packer = Packer {
752        max_size: 0,
753        bytes: Cell::new(b),
754        header: false,
755        offset: Cell::new(0),
756    };
757    let b = packer.unpack_u16().unwrap();
758    assert_eq!(b, 0x0102);
759    assert_eq!(packer.get_offset(), U16_LEN);
760
761    assert!(packer.unpack_u16().is_err());
762}
763
764/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_u16_short --exact --show-output
765/// ref. "avalanchego/utils/wrappers.TestPacker"
766#[test]
767fn test_pack_u16_short() {
768    let packer = Packer {
769        max_size: 3,
770        bytes: Cell::new(BytesMut::with_capacity(0)),
771        header: false,
772        offset: Cell::new(0),
773    };
774
775    packer.pack_u16(17).unwrap();
776    assert_eq!(packer.bytes_len(), 2);
777    assert!(packer.pack_u16(1).is_err());
778
779    let b = packer.take_bytes();
780    let expected = [0x00, 17];
781    assert_eq!(&b[..], &expected[..]);
782
783    let s: Vec<u8> = vec![0x00, 17];
784    let b = BytesMut::from(&s[..]);
785    let packer = Packer {
786        max_size: 0,
787        bytes: Cell::new(b),
788        header: false,
789        offset: Cell::new(0),
790    };
791    let b = packer.unpack_u16().unwrap();
792    assert_eq!(b, 17);
793    assert_eq!(packer.get_offset(), U16_LEN);
794
795    let packer = Packer::new_with_header(4 + U16_LEN, 0);
796    packer.pack_u16(17).unwrap();
797    let expected = [0x00, 0x00, 0x00, 0x02, 0x00, 17];
798    assert_eq!(&packer.take_bytes()[..], &expected[..]);
799}
800
801/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_u32 --exact --show-output
802/// ref. "avalanchego/utils/wrappers.TestPackerPackInt"
803#[test]
804fn test_pack_u32() {
805    let packer = Packer {
806        max_size: U32_LEN,
807        bytes: Cell::new(BytesMut::with_capacity(0)),
808        header: false,
809        offset: Cell::new(0),
810    };
811    packer.pack_u32(0x01020304).unwrap();
812    assert_eq!(packer.bytes_len(), U32_LEN);
813    assert!(packer.pack_u32(0x05060708).is_err());
814
815    let b = packer.take_bytes();
816    assert_eq!(&b[..], b"\x01\x02\x03\x04");
817    let expected = [0x01, 0x02, 0x03, 0x04];
818    assert_eq!(&b[..], &expected[..]);
819}
820
821/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_u32 --exact --show-output
822/// ref. "avalanchego/utils/wrappers.TestPackerUnpackInt"
823#[test]
824fn test_unpack_u32() {
825    let s: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
826    let b = BytesMut::from(&s[..]);
827    let packer = Packer {
828        max_size: 0,
829        bytes: Cell::new(b),
830        header: false,
831        offset: Cell::new(0),
832    };
833    assert_eq!(packer.unpack_u32().unwrap(), 0x01020304);
834    assert_eq!(packer.get_offset(), U32_LEN);
835    assert!(packer.unpack_u32().is_err());
836}
837
838/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_u64 --exact --show-output
839/// ref. "avalanchego/utils/wrappers.TestPackerPackLong"
840#[test]
841fn test_pack_u64() {
842    let packer = Packer {
843        max_size: U64_LEN,
844        bytes: Cell::new(BytesMut::with_capacity(0)),
845        header: false,
846        offset: Cell::new(0),
847    };
848    packer.pack_u64(0x0102030405060708).unwrap();
849    assert_eq!(packer.bytes_len(), U64_LEN);
850
851    // beyond max size
852    assert!(packer.pack_u64(0x090a0b0c0d0e0f00).is_err());
853
854    let b = packer.take_bytes();
855    assert_eq!(&b[..], b"\x01\x02\x03\x04\x05\x06\x07\x08");
856    let expected = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
857    assert_eq!(&b[..], &expected[..]);
858
859    let packer = Packer::new_with_header(4 + U64_LEN, 0);
860    packer.pack_u64(0x0102030405060708).unwrap();
861    let expected = [
862        0x00, 0x00, 0x00, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
863    ];
864    assert_eq!(&packer.take_bytes()[..], &expected[..]);
865}
866
867/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_u64 --exact --show-output
868/// ref. "avalanchego/utils/wrappers.TestPackerUnpackLong"
869#[test]
870fn test_unpack_u64() {
871    let s: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
872    let b = BytesMut::from(&s[..]);
873    let packer = Packer {
874        max_size: 0,
875        bytes: Cell::new(b),
876        header: false,
877        offset: Cell::new(0),
878    };
879    assert_eq!(packer.unpack_u64().unwrap(), 0x0102030405060708);
880    assert_eq!(packer.get_offset(), U64_LEN);
881    assert!(packer.unpack_u64().is_err());
882}
883
884/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_bool --exact --show-output
885/// ref. "avalanchego/utils/wrappers.TestPackBool"
886/// ref. "avalanchego/utils/wrappers.TestPackerPackBool"
887#[test]
888fn test_pack_bool() {
889    let packer = Packer {
890        max_size: 3,
891        bytes: Cell::new(BytesMut::with_capacity(0)),
892        header: false,
893        offset: Cell::new(0),
894    };
895    packer.pack_bool(false).unwrap();
896    packer.pack_bool(true).unwrap();
897    packer.pack_bool(false).unwrap();
898    assert_eq!(packer.bytes_len(), 3);
899
900    assert!(packer.pack_bool(true).is_err());
901
902    let b = packer.take_bytes();
903    assert_eq!(&b[..], b"\x00\x01\x00");
904    let expected = [0x00, 0x01, 0x00];
905    assert_eq!(&b[..], &expected[..]);
906
907    let b = BytesMut::from(&expected[..]);
908    let packer = Packer {
909        max_size: 0,
910        bytes: Cell::new(b),
911        header: false,
912        offset: Cell::new(0),
913    };
914    assert!(!packer.unpack_bool().unwrap());
915    assert!(packer.unpack_bool().unwrap());
916    assert!(!packer.unpack_bool().unwrap());
917
918    let packer = Packer::new_with_header(4 + 3, 0);
919    packer.pack_bool(false).unwrap();
920    packer.pack_bool(true).unwrap();
921    packer.pack_bool(false).unwrap();
922    let expected = [0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00];
923    assert_eq!(&packer.take_bytes()[..], &expected[..]);
924}
925
926/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_bool --exact --show-output
927/// ref. "avalanchego/utils/wrappers.TestPackBool"
928/// ref. "avalanchego/utils/wrappers.TestPackerUnpackBool"
929#[test]
930fn test_unpack_bool() {
931    let s = [0x01];
932    let b = BytesMut::from(&s[..]);
933    let packer = Packer {
934        max_size: 0,
935        bytes: Cell::new(b),
936        header: false,
937        offset: Cell::new(0),
938    };
939    assert!(packer.unpack_bool().unwrap());
940    assert_eq!(packer.get_offset(), BOOL_LEN);
941    assert!(packer.unpack_bool().is_err());
942}
943
944/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_bytes --exact --show-output
945/// ref. "avalanchego/utils/wrappers.TestPackerPackFixedBytes"
946#[test]
947fn test_pack_bytes() {
948    let packer = Packer {
949        max_size: 8,
950        bytes: Cell::new(BytesMut::with_capacity(0)),
951        header: false,
952        offset: Cell::new(0),
953    };
954
955    let s = "Avax";
956    packer.pack_bytes(s.as_bytes()).unwrap();
957    assert_eq!(packer.bytes_len(), 4);
958
959    packer.pack_bytes(s.as_bytes()).unwrap();
960    assert_eq!(packer.bytes_len(), 8);
961
962    // beyond max size
963    assert!(packer.pack_bytes(s.as_bytes()).is_err());
964
965    let b = packer.take_bytes();
966    assert_eq!(&b[..], b"AvaxAvax");
967    let expected = [65, 118, 97, 120, 65, 118, 97, 120];
968    assert_eq!(&b[..], &expected[..]);
969
970    let packer = Packer::new_with_header(4 + 8, 0);
971    packer.pack_bytes(s.as_bytes()).unwrap();
972    packer.pack_bytes(s.as_bytes()).unwrap();
973    let expected = [0x00, 0x00, 0x00, 0x08, 65, 118, 97, 120, 65, 118, 97, 120];
974    assert_eq!(&packer.take_bytes()[..], &expected[..]);
975}
976
977/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_bytes --exact --show-output
978/// ref. "avalanchego/utils/wrappers.TestPackerUnpackFixedBytes"
979#[test]
980fn test_unpack_bytes() {
981    let s: Vec<u8> = vec![65, 118, 97, 120];
982    let b = BytesMut::from(&s[..]);
983    let packer = Packer {
984        max_size: 0,
985        bytes: Cell::new(b),
986        header: false,
987        offset: Cell::new(0),
988    };
989    let b = packer.unpack_bytes(4).unwrap();
990    assert_eq!(&b[..], b"Avax");
991    assert_eq!(packer.get_offset(), 4);
992    assert!(packer.unpack_bytes(4).is_err());
993}
994
995/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_bytes_with_header --exact --show-output
996/// ref. "avalanchego/utils/wrappers.TestPackerPackBytes"
997#[test]
998fn test_pack_bytes_with_header() {
999    let packer = Packer {
1000        max_size: 8,
1001        bytes: Cell::new(BytesMut::with_capacity(0)),
1002        header: false,
1003        offset: Cell::new(0),
1004    };
1005
1006    let s = "Avax";
1007    packer.pack_bytes_with_header(s.as_bytes()).unwrap();
1008    assert_eq!(packer.bytes_len(), 8);
1009
1010    // beyond max size
1011    assert!(packer.pack_bytes_with_header(s.as_bytes()).is_err());
1012
1013    let b = packer.take_bytes();
1014    assert_eq!(&b[..], b"\x00\x00\x00\x04Avax");
1015    let expected = [0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120];
1016    assert_eq!(&b[..], &expected[..]);
1017
1018    let packer = Packer::new_with_header(4 + 8, 0);
1019    packer.pack_bytes_with_header(s.as_bytes()).unwrap();
1020    let expected = [
1021        0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120,
1022    ];
1023    assert_eq!(&packer.take_bytes()[..], &expected[..]);
1024}
1025
1026/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_bytes_with_header --exact --show-output
1027/// ref. "avalanchego/utils/wrappers.TestPackerUnpackBytes"
1028#[test]
1029fn test_unpack_bytes_with_header() {
1030    let s: Vec<u8> = vec![0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120];
1031    let b = BytesMut::from(&s[..]);
1032    let packer = Packer {
1033        max_size: 0,
1034        bytes: Cell::new(b),
1035        header: false,
1036        offset: Cell::new(0),
1037    };
1038    let b = packer.unpack_bytes_with_header().unwrap();
1039    assert_eq!(&b[..], b"Avax");
1040    assert_eq!(packer.get_offset(), 8);
1041    assert!(packer.unpack_bytes_with_header().is_err());
1042}
1043
1044/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_2d_bytes --exact --show-output
1045/// ref. "avalanchego/utils/wrappers.TestPackerPackFixedByteSlices"
1046#[test]
1047fn test_pack_2d_bytes() {
1048    let packer = Packer {
1049        max_size: 12,
1050        bytes: Cell::new(BytesMut::with_capacity(0)),
1051        header: false,
1052        offset: Cell::new(0),
1053    };
1054
1055    // first 4-byte is for length
1056    let s1 = "Avax";
1057    let s2 = "Evax";
1058    packer
1059        .pack_2d_bytes(vec![Vec::from(s1.as_bytes()), Vec::from(s2.as_bytes())])
1060        .unwrap();
1061    assert_eq!(packer.bytes_len(), 12);
1062
1063    // beyond max size
1064    assert!(packer
1065        .pack_2d_bytes(vec![Vec::from(s1.as_bytes()), Vec::from(s2.as_bytes()),])
1066        .is_err());
1067
1068    let b = packer.take_bytes();
1069    assert_eq!(&b[..], b"\x00\x00\x00\x02AvaxEvax");
1070    let expected = [0x00, 0x00, 0x00, 0x02, 65, 118, 97, 120, 69, 118, 97, 120];
1071    assert_eq!(&b[..], &expected[..]);
1072
1073    let packer = Packer::new_with_header(4 + 12, 0);
1074    packer
1075        .pack_2d_bytes(vec![Vec::from(s1.as_bytes()), Vec::from(s2.as_bytes())])
1076        .unwrap();
1077    let expected = [
1078        0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 65, 118, 97, 120, 69, 118, 97, 120,
1079    ];
1080    assert_eq!(&packer.take_bytes()[..], &expected[..]);
1081}
1082
1083/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_2d_bytes --exact --show-output
1084/// ref. "avalanchego/utils/wrappers.TestPackerUnpackFixedByteSlices"
1085#[test]
1086fn test_unpack_2d_bytes() {
1087    let s: Vec<u8> = vec![0x00, 0x00, 0x00, 0x02, 65, 118, 97, 120, 69, 118, 97, 120];
1088    let b = BytesMut::from(&s[..]);
1089    let packer = Packer {
1090        max_size: 0,
1091        bytes: Cell::new(b),
1092        header: false,
1093        offset: Cell::new(0),
1094    };
1095    let b = packer.unpack_2d_bytes(4).unwrap();
1096    assert_eq!(
1097        &b[..],
1098        vec![Vec::from("Avax".as_bytes()), Vec::from("Evax".as_bytes()),]
1099    );
1100    assert_eq!(packer.get_offset(), 12);
1101    assert!(packer.unpack_2d_bytes(4).is_err());
1102}
1103
1104/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_2d_bytes_with_header --exact --show-output
1105#[test]
1106fn test_pack_2d_bytes_with_header() {
1107    let packer = Packer {
1108        max_size: 1024,
1109        bytes: Cell::new(BytesMut::with_capacity(0)),
1110        header: false,
1111        offset: Cell::new(0),
1112    };
1113
1114    // first 4-byte is for length
1115    // two more 4-bytes for each length
1116    let s1 = "Avax";
1117    let s2 = "Evax";
1118    packer
1119        .pack_2d_bytes_with_header(vec![Vec::from(s1.as_bytes()), Vec::from(s2.as_bytes())])
1120        .unwrap();
1121    assert_eq!(packer.bytes_len(), 20); // 4*3 + 4*2
1122
1123    let b = packer.take_bytes();
1124    assert_eq!(
1125        &b[..],
1126        b"\x00\x00\x00\x02\x00\x00\x00\x04Avax\x00\x00\x00\x04Evax"
1127    );
1128    let expected = [
1129        0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120, 0x00, 0x00, 0x00, 0x04,
1130        69, 118, 97, 120,
1131    ];
1132    assert_eq!(&b[..], &expected[..]);
1133
1134    let packer = Packer::new_with_header(4 + 20, 0);
1135    packer
1136        .pack_2d_bytes_with_header(vec![Vec::from(s1.as_bytes()), Vec::from(s2.as_bytes())])
1137        .unwrap();
1138    let expected = [
1139        0x00, 0x00, 0x00, 20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120,
1140        0x00, 0x00, 0x00, 0x04, 69, 118, 97, 120,
1141    ];
1142    assert_eq!(&packer.take_bytes()[..], &expected[..]);
1143}
1144
1145/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_unpack_2d_bytes_with_header --exact --show-output
1146#[test]
1147fn test_unpack_2d_bytes_with_header() {
1148    let s: Vec<u8> = vec![
1149        0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 65, 118, 97, 120, 0x00, 0x00, 0x00, 0x04,
1150        69, 118, 97, 120,
1151    ];
1152    let b = BytesMut::from(&s[..]);
1153    let packer = Packer {
1154        max_size: 0,
1155        bytes: Cell::new(b),
1156        header: false,
1157        offset: Cell::new(0),
1158    };
1159    let b = packer.unpack_2d_bytes_with_header().unwrap();
1160    assert_eq!(
1161        &b[..],
1162        vec![Vec::from("Avax".as_bytes()), Vec::from("Evax".as_bytes()),]
1163    );
1164    assert_eq!(packer.get_offset(), 20);
1165    assert!(packer.unpack_2d_bytes_with_header().is_err());
1166}
1167
1168/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_2d_bytes_with_header_123 --exact --show-output
1169/// ref. "avalanchego/utils/wrappers.TestPacker2DByteSlice"
1170#[test]
1171fn test_pack_2d_bytes_with_header_123() {
1172    // case 1; empty
1173    let packer = Packer {
1174        max_size: 1024,
1175        bytes: Cell::new(BytesMut::with_capacity(0)),
1176        header: false,
1177        offset: Cell::new(0),
1178    };
1179    packer.pack_2d_bytes_with_header(vec![]).unwrap();
1180    assert_eq!(packer.bytes_len(), 4);
1181    assert!(packer.unpack_2d_bytes_with_header().is_err());
1182
1183    // case 2; only one dimension
1184    let packer = Packer {
1185        max_size: 1024,
1186        bytes: Cell::new(BytesMut::with_capacity(0)),
1187        header: false,
1188        offset: Cell::new(0),
1189    };
1190    packer
1191        .pack_2d_bytes_with_header(vec![vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
1192        .unwrap();
1193    assert_eq!(packer.bytes_len(), 4 + 4 + 10);
1194
1195    let b = packer.take_bytes();
1196    let expected = [0, 0, 0, 1, 0, 0, 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1197    assert_eq!(&b[..], &expected[..]);
1198
1199    let s: Vec<u8> = vec![0, 0, 0, 1, 0, 0, 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1200    let b = BytesMut::from(&s[..]);
1201    let packer = Packer {
1202        max_size: 1024,
1203        bytes: Cell::new(b),
1204        header: false,
1205        offset: Cell::new(0),
1206    };
1207    let b = packer.unpack_2d_bytes_with_header().unwrap();
1208    assert_eq!(&b[..], vec![vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]);
1209    assert_eq!(packer.get_offset(), 4 + 4 + 10);
1210
1211    // case 3; two dimensions
1212    let packer = Packer {
1213        max_size: 1024,
1214        bytes: Cell::new(BytesMut::with_capacity(0)),
1215        header: false,
1216        offset: Cell::new(0),
1217    };
1218    packer
1219        .pack_2d_bytes_with_header(vec![
1220            vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1221            vec![11, 12, 3, 4, 5, 6, 7, 8, 9, 10],
1222        ])
1223        .unwrap();
1224    assert_eq!(packer.bytes_len(), 4 + 4 + 10 + 4 + 10);
1225
1226    let b = packer.take_bytes();
1227    let expected = [
1228        0, 0, 0, 2, 0, 0, 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 10, 11, 12, 3, 4, 5, 6, 7,
1229        8, 9, 10,
1230    ];
1231    assert_eq!(&b[..], &expected[..]);
1232
1233    let s: Vec<u8> = vec![
1234        0, 0, 0, 2, 0, 0, 0, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, 10, 11, 12, 3, 4, 5, 6, 7,
1235        8, 9, 10,
1236    ];
1237    let b = BytesMut::from(&s[..]);
1238    let packer = Packer {
1239        max_size: 1024,
1240        bytes: Cell::new(b),
1241        header: false,
1242        offset: Cell::new(0),
1243    };
1244    let b = packer.unpack_2d_bytes_with_header().unwrap();
1245    assert_eq!(
1246        &b[..],
1247        vec![
1248            vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1249            vec![11, 12, 3, 4, 5, 6, 7, 8, 9, 10],
1250        ]
1251    );
1252    assert_eq!(packer.get_offset(), 4 + 4 + 10 + 4 + 10);
1253}
1254
1255/// RUST_LOG=debug cargo test --package avalanche-types --lib -- packer::test_pack_str --exact --show-output
1256/// ref. "avalanchego/utils/wrappers.TestPackerString"
1257#[test]
1258fn test_pack_str() {
1259    let packer = Packer {
1260        max_size: 6,
1261        bytes: Cell::new(BytesMut::with_capacity(0)),
1262        header: false,
1263        offset: Cell::new(0),
1264    };
1265
1266    let s = "Avax";
1267    packer.pack_str(s).unwrap();
1268    assert_eq!(packer.bytes_len(), 2 + 4);
1269
1270    // beyond max size
1271    assert!(packer.pack_str(s).is_err());
1272
1273    let b = packer.take_bytes();
1274    assert_eq!(&b[..], b"\x00\x04Avax");
1275    let expected = [0x00, 0x04, 65, 118, 97, 120];
1276    assert_eq!(&b[..], &expected[..]);
1277
1278    let packer = Packer::new_with_header(4 + 6, 0);
1279    packer.pack_str(s).unwrap();
1280    let expected = [0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 65, 118, 97, 120];
1281    assert_eq!(&packer.take_bytes()[..], &expected[..]);
1282}