A few additions to buf, errors, and restore varint from attic.

This commit is contained in:
Adam Ierymenko
2023-09-29 18:14:16 -04:00
parent c4b1cc100b
commit 336c7c9dd6
4 changed files with 128 additions and 2 deletions
+8 -2
View File
@@ -46,6 +46,11 @@ impl Buf {
}
}
#[inline(always)]
pub fn iter(&self) -> impl Iterator<Item = &u8> {
self.as_slice().iter()
}
#[inline(always)]
pub fn len(&self) -> usize {
unsafe { *self.0.as_ptr() as usize }
@@ -90,11 +95,12 @@ impl Buf {
#[inline]
#[must_use]
pub fn append(&mut self, buf: &[u8]) -> bool {
let new_len = self.len() + buf.len();
let old_len = self.len();
let new_len = old_len + buf.len();
if new_len <= self.capacity() {
unsafe {
*self.0.as_ptr() = new_len as u32;
copy_nonoverlapping(buf.as_ptr(), self.0.as_ptr().cast::<u8>().add(8), buf.len())
copy_nonoverlapping(buf.as_ptr(), self.0.as_ptr().cast::<u8>().add(8 + old_len), buf.len())
};
true
} else {
+17
View File
@@ -9,6 +9,23 @@
use std::error::Error;
use std::fmt::{Debug, Display};
pub struct InvalidStateError;
impl Display for InvalidStateError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("InvalidStateError")
}
}
impl Debug for InvalidStateError {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as Display>::fmt(self, f)
}
}
impl Error for InvalidStateError {}
pub struct InvalidFormatError;
impl Display for InvalidFormatError {
+1
View File
@@ -23,6 +23,7 @@ pub mod ringbuffer;
pub mod str;
pub mod sync;
pub mod tofrombytes;
pub mod varint;
/// Initial value that should be used for monotonic tick time variables.
pub const NEVER_HAPPENED_TICKS: i64 = i64::MIN / 2;
+102
View File
@@ -0,0 +1,102 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::io::{Read, Write};
pub const VARINT_MAX_SIZE_BYTES: usize = 10;
/// Encode an integer as a varint.
///
/// WARNING: if the supplied byte slice does not have at least 10 bytes available this may panic.
/// This is checked in debug mode by an assertion.
#[inline]
pub fn encode(b: &mut [u8], mut v: u64) -> usize {
debug_assert!(b.len() >= VARINT_MAX_SIZE_BYTES);
let mut i = 0;
loop {
if v > 0x7f {
b[i] = (v as u8) & 0x7f;
i += 1;
v = v.wrapping_shr(7);
} else {
b[i] = (v as u8) | 0x80;
i += 1;
break;
}
}
i
}
/// Write a variable length integer, which can consume up to 10 bytes.
#[inline]
pub fn write<W: Write>(w: &mut W, v: u64) -> std::io::Result<()> {
let mut b = [0_u8; VARINT_MAX_SIZE_BYTES];
let i = encode(&mut b, v);
w.write_all(&b[0..i])
}
/// Dencode up to 10 bytes as a varint.
///
/// if the supplied byte slice does not contain a valid varint encoding this will return None.
/// if the supplied byte slice is shorter than expected this will return None.
#[inline]
pub fn decode(b: &[u8]) -> Option<(u64, usize)> {
let mut v = 0_u64;
let mut pos = 0;
let mut i = 0_usize;
while i < b.len() && i < VARINT_MAX_SIZE_BYTES {
let b = b[i];
i += 1;
if b <= 0x7f {
v |= (b as u64).wrapping_shl(pos);
pos += 7;
} else {
v |= ((b & 0x7f) as u64).wrapping_shl(pos);
return Some((v, i));
}
}
None
}
/// Read a variable length integer, returning the value and the number of bytes written.
#[inline]
pub fn read<R: Read>(r: &mut R) -> std::io::Result<(u64, usize)> {
let mut v = 0_u64;
let mut buf = [0_u8; 1];
let mut pos = 0;
let mut i = 0_usize;
loop {
r.read_exact(&mut buf)?;
let b = buf[0];
i += 1;
if b <= 0x7f {
v |= (b as u64).wrapping_shl(pos);
pos += 7;
} else {
v |= ((b & 0x7f) as u64).wrapping_shl(pos);
return Ok((v, i));
}
}
}
#[cfg(test)]
mod tests {
use crate::varint::*;
#[test]
fn varint() {
let mut t: Vec<u8> = Vec::new();
for i in 0..131072 {
t.clear();
let ii = (u64::MAX / 131072) * i;
assert!(write(&mut t, ii).is_ok());
let mut t2 = t.as_slice();
assert_eq!(read(&mut t2).unwrap().0, ii);
}
}
}