cashweb_bitcoin/
var_int.rs

1//! This module contains the [`VarInt`] struct which represents a variable-length integer.
2//! It enjoys [`Encodable`] and [`Decodable`].
3
4use bytes::{Buf, BufMut};
5use thiserror::Error;
6
7use super::{Decodable, Encodable};
8
9/// Error associated with [`VarInt`] deserialization.
10#[derive(Clone, Debug, PartialEq, Eq, Error)]
11pub enum DecodeError {
12    /// Buffer supplied was too short
13    #[error("varint too short")]
14    TooShort,
15    /// The [`VarInt`] supplied was non-minimal.
16    #[error("varint non-minimal")]
17    NonMinimal,
18}
19
20/// Represents a variable-length integer.
21#[derive(Clone, Debug, PartialEq)]
22pub struct VarInt(pub u64);
23
24impl Into<u64> for VarInt {
25    fn into(self) -> u64 {
26        self.0
27    }
28}
29
30impl Encodable for VarInt {
31    #[inline]
32    fn encoded_len(&self) -> usize {
33        match self.0 {
34            0..=0xfc => 1,
35            0xfd..=0xffff => 3,
36            0x10000..=0xffffffff => 5,
37            _ => 9,
38        }
39    }
40
41    #[inline]
42    fn encode_raw<B: BufMut>(&self, buf: &mut B) {
43        match self.0 {
44            0..=0xfc => {
45                buf.put_uint_le(self.0, 1);
46            }
47            0xfd..=0xffff => {
48                buf.put_u8(0xfd);
49                buf.put_uint_le(self.0, 2);
50            }
51            0x10000..=0xffffffff => {
52                buf.put_u8(0xfe);
53                buf.put_uint_le(self.0, 4);
54            }
55            _ => {
56                buf.put_u8(0xff);
57                buf.put_u64_le(self.0);
58            }
59        }
60    }
61}
62
63impl Decodable for VarInt {
64    type Error = DecodeError;
65
66    /// Parse variable-length integer.
67    #[inline]
68    fn decode<B: Buf>(buf: &mut B) -> Result<Self, Self::Error> {
69        if !buf.has_remaining() {
70            return Err(Self::Error::TooShort);
71        }
72        let first_byte = buf.get_u8();
73        match first_byte {
74            0xff => {
75                if buf.remaining() < 8 {
76                    return Err(Self::Error::TooShort);
77                }
78                let x = buf.get_u64_le();
79                if x < 0x100000000 {
80                    Err(Self::Error::NonMinimal)
81                } else {
82                    Ok(Self(x))
83                }
84            }
85            0xfe => {
86                if buf.remaining() < 4 {
87                    return Err(Self::Error::TooShort);
88                }
89                let x = buf.get_uint_le(4);
90                if x < 0x10000 {
91                    Err(Self::Error::NonMinimal)
92                } else {
93                    Ok(Self(x))
94                }
95            }
96            0xfd => {
97                if buf.remaining() < 2 {
98                    return Err(Self::Error::TooShort);
99                }
100                let x = buf.get_uint_le(2);
101                if x < 0xfd {
102                    Err(Self::Error::NonMinimal)
103                } else {
104                    Ok(Self(x))
105                }
106            }
107            n => Ok(VarInt(n.into())),
108        }
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn encode() {
118        let var_int = VarInt(10);
119        let capacity = var_int.encoded_len();
120        let mut raw = Vec::with_capacity(capacity);
121        var_int.encode(&mut raw).unwrap();
122        assert_eq!(raw, vec![10u8]);
123
124        let var_int = VarInt(0xfc);
125        let mut raw = Vec::with_capacity(var_int.encoded_len());
126        var_int.encode_raw(&mut raw);
127        assert_eq!(raw, vec![0xfcu8]);
128
129        let var_int = VarInt(0xfd);
130        let mut raw = Vec::with_capacity(var_int.encoded_len());
131        var_int.encode_raw(&mut raw);
132        assert_eq!(raw, vec![0xfdu8, 0xfd, 0]);
133
134        let var_int = VarInt(0xfff);
135        let mut raw = Vec::with_capacity(var_int.encoded_len());
136        var_int.encode_raw(&mut raw);
137        assert_eq!(raw, vec![0xfdu8, 0xff, 0xf]);
138
139        let var_int = VarInt(0xf0f0f0f);
140        let mut raw = Vec::with_capacity(var_int.encoded_len());
141        var_int.encode_raw(&mut raw);
142        assert_eq!(raw, vec![0xfeu8, 0xf, 0xf, 0xf, 0xf]);
143
144        let var_int = VarInt(0xf0f0f0f0f0e0);
145        let mut raw = Vec::with_capacity(var_int.encoded_len());
146        var_int.encode_raw(&mut raw);
147        assert_eq!(raw, vec![0xffu8, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0, 0]);
148    }
149}