Skip to main content

bsv_primitives/util/
mod.rs

1//! Utility types for binary serialization.
2//!
3//! Provides VarInt encoding/decoding, `BsvReader` and `BsvWriter` structs
4//! for reading/writing Bitcoin protocol binary data, and byte manipulation
5//! helpers used in transaction serialization.
6//! Ported from the Go BSV SDK (`util` package).
7
8use crate::PrimitivesError;
9
10// ---------------------------------------------------------------------------
11// VarInt
12// ---------------------------------------------------------------------------
13
14/// A Bitcoin protocol variable-length integer.
15///
16/// VarInt is used in transaction data to indicate the number of upcoming fields
17/// or the length of an upcoming field. The encoding uses 1, 3, 5, or 9 bytes
18/// depending on the magnitude of the value.
19///
20/// See <http://learnmeabitcoin.com/glossary/varint>
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct VarInt(pub u64);
23
24impl VarInt {
25    /// Decode a VarInt from a byte slice.
26    ///
27    /// Returns the decoded value and the number of bytes consumed.
28    ///
29    /// # Arguments
30    /// * `data` - Byte slice starting with a VarInt encoding.
31    ///
32    /// # Returns
33    /// `Ok((VarInt, bytes_consumed))` or `Err` if the slice is too short.
34    ///
35    /// # Panics
36    /// None — all bounds are checked.
37    pub fn from_bytes(data: &[u8]) -> Result<(Self, usize), PrimitivesError> {
38        if data.is_empty() {
39            return Err(PrimitivesError::UnexpectedEof);
40        }
41        match data[0] {
42            0xff => {
43                if data.len() < 9 {
44                    return Err(PrimitivesError::UnexpectedEof);
45                }
46                let val = u64::from_le_bytes([
47                    data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
48                ]);
49                Ok((VarInt(val), 9))
50            }
51            0xfe => {
52                if data.len() < 5 {
53                    return Err(PrimitivesError::UnexpectedEof);
54                }
55                let val = u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as u64;
56                Ok((VarInt(val), 5))
57            }
58            0xfd => {
59                if data.len() < 3 {
60                    return Err(PrimitivesError::UnexpectedEof);
61                }
62                let val = u16::from_le_bytes([data[1], data[2]]) as u64;
63                Ok((VarInt(val), 3))
64            }
65            b => Ok((VarInt(b as u64), 1)),
66        }
67    }
68
69    /// Return the wire-format byte length of this VarInt.
70    ///
71    /// # Returns
72    /// 1, 3, 5, or 9 depending on the value.
73    pub fn length(&self) -> usize {
74        if self.0 < 253 {
75            1
76        } else if self.0 < 65536 {
77            3
78        } else if self.0 < 4294967296 {
79            5
80        } else {
81            9
82        }
83    }
84
85    /// Encode the VarInt into a new byte vector.
86    ///
87    /// # Returns
88    /// A `Vec<u8>` of 1, 3, 5, or 9 bytes.
89    pub fn to_bytes(&self) -> Vec<u8> {
90        let mut buf = vec![0u8; self.length()];
91        self.put_bytes(&mut buf);
92        buf
93    }
94
95    /// Write the VarInt into a destination buffer.
96    ///
97    /// The buffer must be at least `self.length()` bytes long.
98    ///
99    /// # Arguments
100    /// * `dst` - Destination buffer to write into.
101    ///
102    /// # Returns
103    /// The number of bytes written.
104    pub fn put_bytes(&self, dst: &mut [u8]) -> usize {
105        let v = self.0;
106        if v < 0xfd {
107            dst[0] = v as u8;
108            1
109        } else if v < 0x10000 {
110            dst[0] = 0xfd;
111            dst[1..3].copy_from_slice(&(v as u16).to_le_bytes());
112            3
113        } else if v < 0x100000000 {
114            dst[0] = 0xfe;
115            dst[1..5].copy_from_slice(&(v as u32).to_le_bytes());
116            5
117        } else {
118            dst[0] = 0xff;
119            dst[1..9].copy_from_slice(&v.to_le_bytes());
120            9
121        }
122    }
123
124    /// Check if this value is at the upper boundary of a VarInt size class.
125    ///
126    /// Returns how many extra bytes would be needed if the value were
127    /// incremented by 1. Returns -1 at `u64::MAX` (cannot increment).
128    ///
129    /// # Returns
130    /// 0 if not at a boundary, 2 or 4 for size-class transitions, -1 at max.
131    pub fn upper_limit_inc(&self) -> i32 {
132        match self.0 {
133            252 | 65535 => 2,
134            4294967295 => 4,
135            u64::MAX => -1,
136            _ => 0,
137        }
138    }
139
140    /// Return the underlying u64 value.
141    ///
142    /// # Returns
143    /// The integer value.
144    pub fn value(&self) -> u64 {
145        self.0
146    }
147}
148
149impl From<u64> for VarInt {
150    fn from(v: u64) -> Self {
151        VarInt(v)
152    }
153}
154
155impl From<usize> for VarInt {
156    fn from(v: usize) -> Self {
157        VarInt(v as u64)
158    }
159}
160
161// ---------------------------------------------------------------------------
162// BsvReader
163// ---------------------------------------------------------------------------
164
165/// A cursor-based reader for Bitcoin protocol binary data.
166///
167/// Wraps a byte slice and maintains a read position, providing methods
168/// to read fixed-size integers and VarInt values in little-endian order.
169pub struct BsvReader<'a> {
170    data: &'a [u8],
171    pos: usize,
172}
173
174impl<'a> BsvReader<'a> {
175    /// Create a new reader over the given byte slice.
176    ///
177    /// # Arguments
178    /// * `data` - The byte slice to read from.
179    ///
180    /// # Returns
181    /// A `BsvReader` positioned at the start of the data.
182    pub fn new(data: &'a [u8]) -> Self {
183        BsvReader { data, pos: 0 }
184    }
185
186    /// Read `n` bytes and advance the position.
187    ///
188    /// # Arguments
189    /// * `n` - Number of bytes to read.
190    ///
191    /// # Returns
192    /// A byte slice of length `n`, or an error if insufficient data remains.
193    pub fn read_bytes(&mut self, n: usize) -> Result<&'a [u8], PrimitivesError> {
194        if self.pos + n > self.data.len() {
195            return Err(PrimitivesError::UnexpectedEof);
196        }
197        let slice = &self.data[self.pos..self.pos + n];
198        self.pos += n;
199        Ok(slice)
200    }
201
202    /// Read a single byte and advance the position.
203    ///
204    /// # Returns
205    /// The byte value, or an error if no data remains.
206    pub fn read_u8(&mut self) -> Result<u8, PrimitivesError> {
207        let bytes = self.read_bytes(1)?;
208        Ok(bytes[0])
209    }
210
211    /// Read a little-endian u16 and advance the position by 2 bytes.
212    ///
213    /// # Returns
214    /// The decoded u16, or an error if insufficient data.
215    pub fn read_u16_le(&mut self) -> Result<u16, PrimitivesError> {
216        let bytes = self.read_bytes(2)?;
217        Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
218    }
219
220    /// Read a little-endian u32 and advance the position by 4 bytes.
221    ///
222    /// # Returns
223    /// The decoded u32, or an error if insufficient data.
224    pub fn read_u32_le(&mut self) -> Result<u32, PrimitivesError> {
225        let bytes = self.read_bytes(4)?;
226        Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
227    }
228
229    /// Read a little-endian u64 and advance the position by 8 bytes.
230    ///
231    /// # Returns
232    /// The decoded u64, or an error if insufficient data.
233    pub fn read_u64_le(&mut self) -> Result<u64, PrimitivesError> {
234        let bytes = self.read_bytes(8)?;
235        Ok(u64::from_le_bytes([
236            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
237        ]))
238    }
239
240    /// Read a VarInt and advance the position accordingly.
241    ///
242    /// # Returns
243    /// The decoded `VarInt`, or an error if insufficient data.
244    pub fn read_varint(&mut self) -> Result<VarInt, PrimitivesError> {
245        let first = self.read_u8()?;
246        match first {
247            0xff => {
248                let val = self.read_u64_le()?;
249                Ok(VarInt(val))
250            }
251            0xfe => {
252                let val = self.read_u32_le()? as u64;
253                Ok(VarInt(val))
254            }
255            0xfd => {
256                let val = self.read_u16_le()? as u64;
257                Ok(VarInt(val))
258            }
259            b => Ok(VarInt(b as u64)),
260        }
261    }
262
263    /// Return the number of bytes remaining.
264    ///
265    /// # Returns
266    /// The count of unread bytes.
267    pub fn remaining(&self) -> usize {
268        self.data.len() - self.pos
269    }
270}
271
272// ---------------------------------------------------------------------------
273// BsvWriter
274// ---------------------------------------------------------------------------
275
276/// A buffer-based writer for Bitcoin protocol binary data.
277///
278/// Wraps a `Vec<u8>` and provides methods to append fixed-size integers
279/// and VarInt values in little-endian order.
280pub struct BsvWriter {
281    buf: Vec<u8>,
282}
283
284impl BsvWriter {
285    /// Create a new empty writer.
286    ///
287    /// # Returns
288    /// A `BsvWriter` with an empty internal buffer.
289    pub fn new() -> Self {
290        BsvWriter { buf: Vec::new() }
291    }
292
293    /// Create a new writer with a pre-allocated capacity.
294    ///
295    /// # Arguments
296    /// * `capacity` - Initial byte capacity of the internal buffer.
297    ///
298    /// # Returns
299    /// A `BsvWriter` with the given capacity.
300    pub fn with_capacity(capacity: usize) -> Self {
301        BsvWriter {
302            buf: Vec::with_capacity(capacity),
303        }
304    }
305
306    /// Append raw bytes to the buffer.
307    ///
308    /// # Arguments
309    /// * `bytes` - The bytes to append.
310    pub fn write_bytes(&mut self, bytes: &[u8]) {
311        self.buf.extend_from_slice(bytes);
312    }
313
314    /// Append a single byte to the buffer.
315    ///
316    /// # Arguments
317    /// * `val` - The byte value.
318    pub fn write_u8(&mut self, val: u8) {
319        self.buf.push(val);
320    }
321
322    /// Append a little-endian u16 (2 bytes) to the buffer.
323    ///
324    /// # Arguments
325    /// * `val` - The u16 value.
326    pub fn write_u16_le(&mut self, val: u16) {
327        self.buf.extend_from_slice(&val.to_le_bytes());
328    }
329
330    /// Append a little-endian u32 (4 bytes) to the buffer.
331    ///
332    /// # Arguments
333    /// * `val` - The u32 value.
334    pub fn write_u32_le(&mut self, val: u32) {
335        self.buf.extend_from_slice(&val.to_le_bytes());
336    }
337
338    /// Append a little-endian u64 (8 bytes) to the buffer.
339    ///
340    /// # Arguments
341    /// * `val` - The u64 value.
342    pub fn write_u64_le(&mut self, val: u64) {
343        self.buf.extend_from_slice(&val.to_le_bytes());
344    }
345
346    /// Append a VarInt to the buffer.
347    ///
348    /// # Arguments
349    /// * `varint` - The VarInt value to encode and append.
350    pub fn write_varint(&mut self, varint: VarInt) {
351        let bytes = varint.to_bytes();
352        self.buf.extend_from_slice(&bytes);
353    }
354
355    /// Consume the writer and return the accumulated bytes.
356    ///
357    /// # Returns
358    /// The internal byte buffer.
359    pub fn into_bytes(self) -> Vec<u8> {
360        self.buf
361    }
362
363    /// Return a reference to the current buffer contents.
364    ///
365    /// # Returns
366    /// A byte slice of the written data.
367    pub fn as_bytes(&self) -> &[u8] {
368        &self.buf
369    }
370
371    /// Return the current length of the buffer.
372    ///
373    /// # Returns
374    /// The number of bytes written so far.
375    pub fn len(&self) -> usize {
376        self.buf.len()
377    }
378
379    /// Check if the buffer is empty.
380    ///
381    /// # Returns
382    /// `true` if no bytes have been written.
383    pub fn is_empty(&self) -> bool {
384        self.buf.is_empty()
385    }
386}
387
388impl Default for BsvWriter {
389    fn default() -> Self {
390        Self::new()
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::*;
397
398    // -- VarInt decode tests (from Go varint_test.go TestDecodeVarInt) --
399
400    /// Helper to convert a u64 to 8 little-endian bytes.
401    fn le_bytes(v: u64) -> Vec<u8> {
402        v.to_le_bytes().to_vec()
403    }
404
405    #[test]
406    fn test_decode_varint() {
407        // 0xff prefix -> reads 8 bytes after prefix -> value 0, size 9
408        let mut input = vec![0xff, 0, 0, 0, 0, 0, 0, 0, 0]; // 1 prefix + 8 data bytes
409        let (vi, sz) = VarInt::from_bytes(&input).unwrap();
410        assert_eq!(vi.0, 0);
411        assert_eq!(sz, 9);
412
413        // 0xfe prefix -> reads 4 bytes after prefix -> value 0, size 5
414        input = vec![0xfe, 0, 0, 0, 0];
415        let (vi, sz) = VarInt::from_bytes(&input).unwrap();
416        assert_eq!(vi.0, 0);
417        assert_eq!(sz, 5);
418
419        // 0xfd prefix -> reads 2 bytes after prefix -> value 0, size 3
420        input = vec![0xfd, 0, 0];
421        let (vi, sz) = VarInt::from_bytes(&input).unwrap();
422        assert_eq!(vi.0, 0);
423        assert_eq!(sz, 3);
424
425        // value 1 -> single byte, size 1
426        let input = le_bytes(1);
427        let (vi, sz) = VarInt::from_bytes(&input).unwrap();
428        assert_eq!(vi.0, 1);
429        assert_eq!(sz, 1);
430    }
431
432    #[test]
433    fn test_decode_varint_too_short() {
434        assert!(VarInt::from_bytes(&[]).is_err());
435        assert!(VarInt::from_bytes(&[0xff, 0, 0]).is_err());
436        assert!(VarInt::from_bytes(&[0xfe, 0]).is_err());
437        assert!(VarInt::from_bytes(&[0xfd]).is_err());
438    }
439
440    // -- VarInt upper-limit-inc tests --
441
442    #[test]
443    fn test_varint_upper_limit_inc() {
444        assert_eq!(VarInt(0).upper_limit_inc(), 0);
445        assert_eq!(VarInt(10).upper_limit_inc(), 0);
446        assert_eq!(VarInt(100).upper_limit_inc(), 0);
447        assert_eq!(VarInt(252).upper_limit_inc(), 2);
448        assert_eq!(VarInt(65535).upper_limit_inc(), 2);
449        assert_eq!(VarInt(4294967295).upper_limit_inc(), 4);
450        assert_eq!(VarInt(u64::MAX).upper_limit_inc(), -1);
451    }
452
453    // -- VarInt byte-length tests --
454
455    #[test]
456    fn test_varint_byte_length() {
457        assert_eq!(VarInt(0).to_bytes().len(), 1); // 1 byte lower
458        assert_eq!(VarInt(252).to_bytes().len(), 1); // 1 byte upper
459        assert_eq!(VarInt(253).to_bytes().len(), 3); // 3 byte lower
460        assert_eq!(VarInt(65535).to_bytes().len(), 3); // 3 byte upper
461        assert_eq!(VarInt(65536).to_bytes().len(), 5); // 5 byte lower
462        assert_eq!(VarInt(4294967295).to_bytes().len(), 5); // 5 byte upper
463        assert_eq!(VarInt(4294967296).to_bytes().len(), 9); // 9 byte lower
464        assert_eq!(VarInt(u64::MAX).to_bytes().len(), 9); // 9 byte upper
465    }
466
467    // -- VarInt size (length) tests --
468
469    #[test]
470    fn test_varint_size() {
471        assert_eq!(VarInt(252).length(), 1);
472        assert_eq!(VarInt(253).length(), 3);
473        assert_eq!(VarInt(65535).length(), 3);
474        assert_eq!(VarInt(65536).length(), 5);
475        assert_eq!(VarInt(4294967295).length(), 5);
476        assert_eq!(VarInt(4294967296).length(), 9);
477    }
478
479    // -- VarInt put_bytes tests --
480
481    #[test]
482    fn test_varint_put_bytes() {
483        let cases: Vec<(u64, Vec<u8>)> = vec![
484            (0, vec![0x00]),
485            (1, vec![0x01]),
486            (252, vec![0xfc]),
487            (253, vec![0xfd, 0xfd, 0x00]),
488            (65535, vec![0xfd, 0xff, 0xff]),
489            (65536, vec![0xfe, 0x00, 0x00, 0x01, 0x00]),
490            (4294967295, vec![0xfe, 0xff, 0xff, 0xff, 0xff]),
491            (
492                4294967296,
493                vec![0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00],
494            ),
495            (
496                u64::MAX,
497                vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
498            ),
499        ];
500
501        for (value, expected) in cases {
502            let vi = VarInt(value);
503            let mut buf = vec![0u8; vi.length()];
504            let n = vi.put_bytes(&mut buf);
505            assert_eq!(n, expected.len(), "put_bytes length mismatch for {}", value);
506            assert_eq!(buf, expected, "put_bytes content mismatch for {}", value);
507            // Verify put_bytes matches to_bytes.
508            assert_eq!(vi.to_bytes(), buf, "to_bytes != put_bytes for {}", value);
509        }
510    }
511
512    // -- BsvReader / BsvWriter round-trip tests --
513
514    #[test]
515    fn test_bsv_reader_writer_roundtrip() {
516        let mut writer = BsvWriter::new();
517        writer.write_u8(0x42);
518        writer.write_u16_le(0x1234);
519        writer.write_u32_le(0xDEADBEEF);
520        writer.write_u64_le(0x0102030405060708);
521        writer.write_varint(VarInt(300));
522        writer.write_bytes(b"hello");
523
524        let data = writer.into_bytes();
525        let mut reader = BsvReader::new(&data);
526
527        assert_eq!(reader.read_u8().unwrap(), 0x42);
528        assert_eq!(reader.read_u16_le().unwrap(), 0x1234);
529        assert_eq!(reader.read_u32_le().unwrap(), 0xDEADBEEF);
530        assert_eq!(reader.read_u64_le().unwrap(), 0x0102030405060708);
531        assert_eq!(reader.read_varint().unwrap(), VarInt(300));
532        assert_eq!(reader.read_bytes(5).unwrap(), b"hello");
533        assert_eq!(reader.remaining(), 0);
534    }
535
536    #[test]
537    fn test_bsv_reader_eof() {
538        let reader_data: &[u8] = &[0x01];
539        let mut reader = BsvReader::new(reader_data);
540        assert!(reader.read_u8().is_ok());
541        assert!(reader.read_u8().is_err());
542    }
543
544    #[test]
545    fn test_bsv_reader_varint_sizes() {
546        // 1-byte varint
547        let mut reader = BsvReader::new(&[0x05]);
548        assert_eq!(reader.read_varint().unwrap(), VarInt(5));
549
550        // 3-byte varint (0xfd prefix)
551        let mut reader = BsvReader::new(&[0xfd, 0x00, 0x01]);
552        assert_eq!(reader.read_varint().unwrap(), VarInt(256));
553
554        // 5-byte varint (0xfe prefix)
555        let mut reader = BsvReader::new(&[0xfe, 0x00, 0x00, 0x01, 0x00]);
556        assert_eq!(reader.read_varint().unwrap(), VarInt(65536));
557
558        // 9-byte varint (0xff prefix)
559        let mut reader = BsvReader::new(&[0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]);
560        assert_eq!(reader.read_varint().unwrap(), VarInt(4294967296));
561    }
562}