bsv_wasm/traits/
varint.rs

1use byteorder::LittleEndian;
2use byteorder::ReadBytesExt;
3use byteorder::WriteBytesExt;
4use std::io::Cursor;
5use std::io::Result;
6
7use crate::OpCodes;
8
9pub trait VarIntReader {
10    fn read_varint(&mut self) -> Result<u64>;
11}
12
13pub trait VarIntWriter {
14    fn write_varint(&mut self, varint: u64) -> std::io::Result<usize>;
15}
16
17pub struct VarInt {}
18
19impl VarInt {
20    pub fn get_varint_size(data_length: u64) -> usize {
21        if data_length <= 252 {
22            1
23        } else if data_length <= 0xffff {
24            2
25        } else if data_length <= 0xffffffff {
26            4
27        } else {
28            8
29        }
30    }
31
32    pub fn get_pushdata_opcode(length: u64) -> Option<OpCodes> {
33        if length <= 0x4b {
34            None
35        } else if length <= 0xff {
36            Some(OpCodes::OP_PUSHDATA1)
37        } else if length <= 0xffff {
38            Some(OpCodes::OP_PUSHDATA2)
39        } else {
40            Some(OpCodes::OP_PUSHDATA4)
41        }
42    }
43
44    pub fn get_varint_bytes(length: u64) -> Vec<u8> {
45        if length <= 252 {
46            vec![length as u8]
47        } else if length <= 0xff {
48            let mut push1 = vec![0xfd];
49            push1.extend((length as u16).to_le_bytes());
50            push1
51        } else if length <= 0xffff {
52            let mut push2 = vec![0xfe];
53            push2.extend((length as u32).to_le_bytes());
54            push2
55        } else {
56            let mut push4 = vec![0xff];
57            push4.extend((length as u64).to_le_bytes());
58            push4
59        }
60    }
61}
62
63impl VarIntReader for Cursor<Vec<u8>> {
64    fn read_varint(&mut self) -> Result<u64> {
65        match self.read_u8() {
66            Ok(0xff) => self.read_u64::<LittleEndian>(),
67            Ok(0xfe) => self.read_u32::<LittleEndian>().map(|x| x as u64),
68            Ok(0xfd) => self.read_u16::<LittleEndian>().map(|x| x as u64),
69            Ok(v) => Ok(v as u64),
70            Err(e) => Err(e),
71        }
72    }
73}
74
75impl VarIntWriter for Cursor<Vec<u8>> {
76    /**
77     * Borrowed from rust-sv by Brenton Gunning
78     */
79    fn write_varint(&mut self, varint: u64) -> Result<usize> {
80        let mut write = || {
81            if varint <= 252 {
82                self.write_u8(varint as u8)
83            } else if varint <= 0xffff {
84                self.write_u8(0xfd).and_then(|_| self.write_u16::<LittleEndian>(varint as u16))
85            } else if varint <= 0xffffffff {
86                self.write_u8(0xfe).and_then(|_| self.write_u32::<LittleEndian>(varint as u32))
87            } else {
88                self.write_u8(0xff).and_then(|_| self.write_u64::<LittleEndian>(varint))
89            }
90        };
91
92        write()?;
93        Ok(varint as usize)
94    }
95}
96
97impl VarIntReader for Vec<u8> {
98    fn read_varint(&mut self) -> Result<u64> {
99        let mut cursor = Cursor::new(&self);
100
101        match cursor.read_u8() {
102            Ok(0xff) => cursor.read_u64::<LittleEndian>(),
103            Ok(0xfe) => cursor.read_u32::<LittleEndian>().map(|x| x as u64),
104            Ok(0xfd) => cursor.read_u16::<LittleEndian>().map(|x| x as u64),
105            Ok(v) => Ok(v as u64),
106            Err(e) => Err(e),
107        }
108    }
109}
110
111impl VarIntWriter for Vec<u8> {
112    /**
113     * Borrowed from rust-sv by Brenton Gunning
114     */
115    fn write_varint(&mut self, varint: u64) -> Result<usize> {
116        let mut write = || {
117            if varint <= 252 {
118                self.write_u8(varint as u8)
119            } else if varint <= 0xffff {
120                self.write_u8(0xfd).and_then(|_| self.write_u16::<LittleEndian>(varint as u16))
121            } else if varint <= 0xffffffff {
122                self.write_u8(0xfe).and_then(|_| self.write_u32::<LittleEndian>(varint as u32))
123            } else {
124                self.write_u8(0xff).and_then(|_| self.write_u64::<LittleEndian>(varint))
125            }
126        };
127
128        write()?;
129        Ok(varint as usize)
130    }
131}
132
133impl VarIntReader for Cursor<&'_ [u8]> {
134    fn read_varint(&mut self) -> Result<u64> {
135        match self.read_u8() {
136            Ok(0xff) => self.read_u64::<LittleEndian>(),
137            Ok(0xfe) => self.read_u32::<LittleEndian>().map(|x| x as u64),
138            Ok(0xfd) => self.read_u16::<LittleEndian>().map(|x| x as u64),
139            Ok(v) => Ok(v as u64),
140            Err(e) => Err(e),
141        }
142    }
143}