unsigned_varint/decode.rs
1// Copyright 2018-2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of
4// this software and associated documentation files (the "Software"), to deal in
5// the Software without restriction, including without limitation the rights to
6// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7// the Software, and to permit persons to whom the Software is furnished to do so,
8// subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
16// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
20//! Basic unsigned-varint decoding.
21
22use core::{self, fmt};
23
24/// Possible decoding errors.
25///
26/// **Note**: The `std` feature is required for the `std::error::Error` impl and the conversion to
27/// `std::io::Error`.
28#[non_exhaustive]
29#[derive(Clone, Debug, PartialEq, Eq)]
30pub enum Error {
31 /// Not enough input bytes.
32 Insufficient,
33 /// Input bytes exceed maximum.
34 Overflow,
35 /// Encoding is not minimal (has trailing zero bytes).
36 NotMinimal,
37}
38
39impl fmt::Display for Error {
40 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41 match self {
42 Error::Insufficient => f.write_str("not enough input bytes"),
43 Error::Overflow => f.write_str("input bytes exceed maximum"),
44 Error::NotMinimal => f.write_str("encoding is not minimal"),
45 }
46 }
47}
48
49/// Only available when the feature `std` is present.
50#[cfg(feature = "std")]
51impl std::error::Error for Error {}
52
53/// Only available when the feature `std` is present.
54#[cfg(feature = "std")]
55impl Into<std::io::Error> for Error {
56 fn into(self) -> std::io::Error {
57 let kind = match self {
58 Error::Insufficient => std::io::ErrorKind::UnexpectedEof,
59 Error::Overflow => std::io::ErrorKind::InvalidData,
60 Error::NotMinimal => std::io::ErrorKind::InvalidData,
61 };
62 std::io::Error::new(kind, self)
63 }
64}
65
66macro_rules! decode {
67 ($buf:expr, $max_bytes:expr, $typ:ident) => {{
68 let mut n = 0;
69 for (i, b) in $buf.iter().cloned().enumerate() {
70 let k = $typ::from(b & 0x7F);
71 n |= k << (i * 7);
72 if is_last(b) {
73 if b == 0 && i > 0 {
74 // If last byte (of a multi-byte varint) is zero, it could have been "more
75 // minimally" encoded by dropping that trailing zero.
76 return Err(Error::NotMinimal);
77 }
78 return Ok((n, &$buf[i + 1..]));
79 }
80 if i == $max_bytes {
81 return Err(Error::Overflow);
82 }
83 }
84 Err(Error::Insufficient)
85 }};
86}
87
88/// Is this the last byte of an unsigned varint?
89#[inline]
90pub fn is_last(b: u8) -> bool {
91 b & 0x80 == 0
92}
93
94/// Decode the given slice as `u8`.
95///
96/// Returns the value and the remaining slice.
97#[inline]
98pub fn u8(buf: &[u8]) -> Result<(u8, &[u8]), Error> {
99 decode!(buf, 1, u8)
100}
101
102/// Decode the given slice as `u16`.
103///
104/// Returns the value and the remaining slice.
105#[inline]
106pub fn u16(buf: &[u8]) -> Result<(u16, &[u8]), Error> {
107 decode!(buf, 2, u16)
108}
109
110/// Decode the given slice as `u32`.
111///
112/// Returns the value and the remaining slice.
113#[inline]
114pub fn u32(buf: &[u8]) -> Result<(u32, &[u8]), Error> {
115 decode!(buf, 4, u32)
116}
117
118/// Decode the given slice as `u64`.
119///
120/// Returns the value and the remaining slice.
121#[inline]
122pub fn u64(buf: &[u8]) -> Result<(u64, &[u8]), Error> {
123 decode!(buf, 9, u64)
124}
125
126/// Decode the given slice as `u128`.
127///
128/// Returns the value and the remaining slice.
129#[inline]
130pub fn u128(buf: &[u8]) -> Result<(u128, &[u8]), Error> {
131 decode!(buf, 18, u128)
132}
133
134/// Decode the given slice as `usize`.
135///
136/// Returns the value and the remaining slice.
137#[inline]
138#[cfg(target_pointer_width = "64")]
139pub fn usize(buf: &[u8]) -> Result<(usize, &[u8]), Error> {
140 u64(buf).map(|(n, i)| (n as usize, i))
141}
142
143/// Decode the given slice as `usize`.
144///
145/// Returns the value and the remaining slice.
146#[inline]
147#[cfg(target_pointer_width = "32")]
148pub fn usize(buf: &[u8]) -> Result<(usize, &[u8]), Error> {
149 u32(buf).map(|(n, i)| (n as usize, i))
150}