blot/
uvar.rs

1// Copyright 2018 Arnau Siches
2//
3// Licensed under the MIT license <LICENSE or http://opensource.org/licenses/MIT>.
4// This file may not be copied, modified, or distributed except according to
5// those terms.
6
7//! Uvar is an implementation of unsigned variable integers.
8//!
9//! https://github.com/multiformats/unsigned-varint
10
11use std::fmt;
12
13const MAXBYTES: usize = 9;
14
15// TODO: Internal representation is a vector for the time being. In the future it might change to
16// either u64 or an array.
17#[derive(Debug, Clone, PartialEq)]
18pub struct Uvar(Vec<u8>);
19
20impl Uvar {
21    /// Constructs a new uvar from a byte list. Use {Uvar::from_bytes} if you need a safe
22    /// constructor.
23    pub fn new(bytes: Vec<u8>) -> Uvar {
24        Uvar(bytes)
25    }
26
27    /// Consumes the list of bytes.
28    ///
29    /// ```
30    /// use blot::uvar::Uvar;
31    ///
32    /// assert_eq!(Uvar::from_bytes(&[0x12]).unwrap().to_bytes(), vec![0x12]);
33    /// ```
34    pub fn to_bytes(self) -> Vec<u8> {
35        self.0
36    }
37
38    /// Transforms a byte list into a uvar.
39    pub fn from_bytes(buffer: &[u8]) -> Result<Uvar, UvarError> {
40        if buffer.len() > MAXBYTES {
41            return Err(UvarError::Overflow);
42        }
43
44        let (n, _) = Uvar::take(buffer)?;
45
46        Ok(n)
47    }
48
49    /// Takes a uvar from a list of bytes and returns it with the rest of bytes.
50    ///
51    /// ```
52    /// use blot::uvar::Uvar;
53    ///
54    /// let buffer = vec![0x12, 0x07, 0x06];
55    /// let (uvar, bytes) = Uvar::take(&buffer).unwrap();
56    ///
57    /// assert_eq!(uvar, Uvar::from_bytes(&[0x12]).unwrap());
58    /// ```
59    pub fn take(buffer: &[u8]) -> Result<(Uvar, &[u8]), UvarError> {
60        for (i, b) in buffer.into_iter().enumerate() {
61            if b & 0x80 == 0 {
62                let code = Uvar((&buffer[..i + 1]).into());
63                let rest = &buffer[i + 1..];
64
65                return Ok((code, rest));
66            }
67
68            if i >= MAXBYTES {
69                return Err(UvarError::Overflow);
70            }
71        }
72
73        Err(UvarError::Underflow)
74    }
75}
76
77impl fmt::LowerHex for Uvar {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        fmt::LowerHex::fmt(&u64::from(self.clone()), f)
80    }
81}
82
83impl fmt::UpperHex for Uvar {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        fmt::UpperHex::fmt(&u64::from(self.clone()), f)
86    }
87}
88
89impl fmt::Binary for Uvar {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        fmt::Binary::fmt(&u64::from(self.clone()), f)
92    }
93}
94
95impl fmt::Display for Uvar {
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        write!(f, "{:02x}", &self)
98    }
99}
100
101impl From<Uvar> for u64 {
102    fn from(uvar: Uvar) -> u64 {
103        let mut n = 0;
104
105        for (i, b) in uvar.to_bytes().iter().enumerate() {
106            n = n << (i * 8) | u64::from(b & 0xFF);
107        }
108
109        n
110    }
111}
112
113/// This conversion consumes full bytes, not 7bit bytes as you would expect from variable integers.
114///
115/// WARNING: This method forces to Big Endian. It hasn't been tested properly with different architectures.
116impl From<u64> for Uvar {
117    fn from(n: u64) -> Uvar {
118        let mut buffer = Vec::with_capacity(MAXBYTES);
119        let mut value = n.to_be();
120
121        while value > 0 {
122            let k = value & 0xFF;
123            if k != 0 {
124                buffer.push(k as u8);
125            }
126
127            value = value >> 8;
128        }
129
130        Uvar(buffer)
131    }
132}
133
134// macro_rules! impl_for_array (($len:expr) => {
135//     impl From<Uvar> for [u8; $len] {
136//         fn from(n: Uvar) -> [u8; $len] {
137//             let mut buffer = [0; $len];
138//             let mut value = n.unbox();
139//             let mut i = 0;
140
141//             while value > 0x7F {
142//                 buffer[i] = (value as u8) | 0x80;
143//                 value >>= 7;
144//                 i += 1;
145//             }
146
147//             buffer[i] = value as u8;
148
149//             buffer
150//         }
151//     }
152// });
153
154// impl_for_array!(9);
155// impl_for_array!(8);
156// impl_for_array!(7);
157// impl_for_array!(6);
158// impl_for_array!(5);
159// impl_for_array!(4);
160// impl_for_array!(3);
161// impl_for_array!(2);
162// impl_for_array!(1);
163
164#[derive(Debug)]
165pub enum UvarError {
166    Overflow,
167    Underflow,
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn from_bytes_single() {
176        let actual = Uvar::from_bytes(&[0x12]).unwrap();
177        let expected = Uvar(vec![0x12]);
178        assert_eq!(actual, expected);
179    }
180
181    #[test]
182    fn from_bytes_multi() {
183        let actual = Uvar::from_bytes(&[0xb2, 0x40]).unwrap();
184        let expected = Uvar(vec![0xb2, 0x40]);
185        assert_eq!(actual, expected);
186    }
187
188    #[test]
189    fn to_bytes() {
190        let actual = Uvar(vec![0xb2, 0x40]).to_bytes();
191        let expected = &[0xb2, 0x40];
192        assert_eq!(&actual, expected);
193    }
194
195    #[test]
196    fn identity() {
197        let actual = Uvar::from_bytes(&[0xb2, 0x40]).unwrap().to_bytes();
198        let expected = &[0xb2, 0x40];
199        assert_eq!(&actual, expected);
200    }
201
202    #[test]
203    fn to_u64() {
204        for (buffer, expected) in &[(vec![0x12], 0x12), (vec![0xb2, 0x40], 0xb240)] {
205            let actual: u64 = Uvar::from_bytes(&buffer).unwrap().into();
206
207            assert_eq!(actual, *expected);
208        }
209    }
210
211    #[test]
212    fn from_u64() {
213        for (buffer, n) in &[(vec![0x12], 0x12), (vec![0xb2, 0x40], 0xb240)] {
214            let num: u64 = *n;
215            let expected = Uvar::from_bytes(&buffer).unwrap();
216            let actual: Uvar = num.into();
217
218            assert_eq!(actual, expected);
219        }
220    }
221
222}