1use crate::ConsensusError;
10use crate::Result;
11use std::io::{Read, Write};
12
13pub const MAX_VARINT: u64 = u64::MAX;
15
16pub fn read_varint<R: Read>(reader: &mut R) -> Result<u64> {
18 let mut buf = [0u8; 1];
19 reader
20 .read_exact(&mut buf)
21 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
22 let first_byte = buf[0];
23
24 match first_byte {
25 0xfd => {
26 let mut buf = [0u8; 2];
27 reader
28 .read_exact(&mut buf)
29 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
30 Ok(u16::from_le_bytes(buf) as u64)
31 }
32 0xfe => {
33 let mut buf = [0u8; 4];
34 reader
35 .read_exact(&mut buf)
36 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
37 Ok(u32::from_le_bytes(buf) as u64)
38 }
39 0xff => {
40 let mut buf = [0u8; 8];
41 reader
42 .read_exact(&mut buf)
43 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
44 Ok(u64::from_le_bytes(buf))
45 }
46 _ => Ok(first_byte as u64),
47 }
48}
49
50pub fn write_varint<W: Write>(writer: &mut W, value: u64) -> Result<usize> {
52 match value {
53 0..=0xfc => {
54 writer
55 .write_all(&[value as u8])
56 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
57 Ok(1)
58 }
59 0xfd..=0xffff => {
60 writer
61 .write_all(&[0xfd])
62 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
63 writer
64 .write_all(&(value as u16).to_le_bytes())
65 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
66 Ok(3)
67 }
68 0x10000..=0xffff_ffff => {
69 writer
70 .write_all(&[0xfe])
71 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
72 writer
73 .write_all(&(value as u32).to_le_bytes())
74 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
75 Ok(5)
76 }
77 _ => {
78 writer
79 .write_all(&[0xff])
80 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
81 writer
82 .write_all(&value.to_le_bytes())
83 .map_err(|e| ConsensusError::Serialization(format!("IO error: {e}").into()))?;
84 Ok(9)
85 }
86 }
87}
88
89pub fn varint_size(value: u64) -> usize {
91 match value {
92 0..=0xfc => 1,
93 0xfd..=0xffff => 3,
94 0x10000..=0xffff_ffff => 5,
95 _ => 9,
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use std::io::Cursor;
103
104 #[test]
105 fn test_varint_roundtrip() {
106 let test_values = vec![
107 0,
108 1,
109 0xfc,
110 0xfd,
111 0xffff,
112 0x10000,
113 0xffff_ffff,
114 0x1_0000_0000,
115 u64::MAX,
116 ];
117
118 for value in test_values {
119 let mut buf = Vec::new();
120 write_varint(&mut buf, value).unwrap();
121 let mut cursor = Cursor::new(&buf);
122 let decoded = read_varint(&mut cursor).unwrap();
123 assert_eq!(value, decoded);
124 }
125 }
126
127 #[test]
128 fn test_varint_size() {
129 assert_eq!(varint_size(0), 1);
130 assert_eq!(varint_size(0xfc), 1);
131 assert_eq!(varint_size(0xfd), 3);
132 assert_eq!(varint_size(0xffff), 3);
133 assert_eq!(varint_size(0x10000), 5);
134 assert_eq!(varint_size(0xffff_ffff), 5);
135 assert_eq!(varint_size(0x1_0000_0000), 9);
136 assert_eq!(varint_size(u64::MAX), 9);
137 }
138}