#![allow(missing_docs)]
use core::mem;
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct VarInt(u64);
impl VarInt {
pub const WIRE_TYPE: WireType = WireType::VarInt;
#[inline(always)]
pub fn uint64(v: u64) -> Self {
VarInt(v)
}
#[inline(always)]
pub fn sint64(v: i64) -> Self {
VarInt(v as u64)
}
#[inline(always)]
pub fn sint64z(v: i64) -> Self {
VarInt((v << 1) as u64 ^ (v >> 63) as u64)
}
#[inline(always)]
pub fn bool(v: bool) -> Self {
VarInt(if v { 1 } else { 0 })
}
#[inline(always)]
pub fn enum32(v: i32) -> Self {
VarInt(v as u64)
}
#[inline(always)]
pub fn field(field_number: u64, wire_type: WireType) -> Self {
VarInt((field_number << 3) | (wire_type as u64))
}
#[inline(always)]
pub fn fill_bytes<'a>(&self, buf: &'a mut [u8; 10]) -> &'a [u8] {
let mut v = self.0;
let mut i = 0;
while v >= 0b1000_0000 {
buf[i] = ((v & 0b0111_1111) | 0b1000_0000) as u8;
i += 1;
v >>= 7;
}
buf[i] = v as u8;
&buf[..i + 1]
}
#[inline(always)]
pub fn len(&self) -> usize {
((((self.0 | 1).leading_zeros() ^ 63) * 9 + 73) / 64) as usize
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct I32(u32);
impl I32 {
pub const WIRE_TYPE: WireType = WireType::I32;
#[inline(always)]
pub fn float(v: f32) -> Self {
I32(v.to_bits())
}
#[inline(always)]
pub fn fixed32(v: u32) -> Self {
I32(v)
}
#[inline(always)]
pub fn sfixed32(v: i32) -> Self {
I32(v as u32)
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; 4] {
self.0.to_le_bytes()
}
#[inline(always)]
pub fn len(&self) -> usize {
mem::size_of::<Self>()
}
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct I64(u64);
impl I64 {
pub const WIRE_TYPE: WireType = WireType::I64;
#[inline(always)]
pub fn double(v: f64) -> Self {
I64(v.to_bits())
}
#[inline(always)]
pub fn fixed64(v: u64) -> Self {
I64(v)
}
#[inline(always)]
pub fn sfixed64(v: i64) -> Self {
I64(v as u64)
}
#[inline(always)]
pub fn to_bytes(&self) -> [u8; 8] {
self.0.to_le_bytes()
}
#[inline(always)]
pub fn len(&self) -> usize {
mem::size_of::<Self>()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WireType {
VarInt = 0,
I64 = 1,
Len = 2,
I32 = 5,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn varint_uint64_len() {
for n in (0u64..(u16::MAX as u64)).into_iter().chain(
[
u32::MAX as u64 - 1,
u32::MAX as u64,
u32::MAX as u64 + 1,
u64::MAX,
]
.into_iter(),
) {
let v = VarInt::uint64(n);
assert_eq!(v.len(), v.fill_bytes(&mut [0; 10]).len(), "{}", n);
}
}
#[test]
fn encode_varint_uint64() {
for (case, expected) in [
(0, &[0u8] as &[u8]),
(1, &[1u8] as &[u8]),
(255, &[255u8, 1u8] as &[u8]),
(
u64::MAX,
&[
255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 1u8,
] as &[u8],
),
] {
let varint = VarInt::uint64(case);
assert_eq!(expected, varint.fill_bytes(&mut [0; 10]), "{}", case);
assert_eq!(
varint.len(),
varint.fill_bytes(&mut [0; 10]).len(),
"{}",
case
);
}
}
#[test]
fn encode_varint_sint64() {
for (case, expected) in [
(0, &[0u8] as &[u8]),
(1, &[1u8] as &[u8]),
(
-1,
&[
255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 1u8,
] as &[u8],
),
(
i64::MIN,
&[
128u8, 128u8, 128u8, 128u8, 128u8, 128u8, 128u8, 128u8, 128u8, 1u8,
] as &[u8],
),
(
i64::MAX,
&[
255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 127u8,
] as &[u8],
),
] {
assert_eq!(
expected,
VarInt::sint64(case).fill_bytes(&mut [0; 10]),
"{}",
case
);
}
}
#[test]
fn encode_varint_sint64z() {
for (case, expected) in [
(0, &[0u8] as &[u8]),
(1, &[2u8] as &[u8]),
(-1, &[1u8] as &[u8]),
(
i64::MIN,
&[
255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 1u8,
] as &[u8],
),
(
i64::MAX,
&[
254u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 1u8,
] as &[u8],
),
] {
assert_eq!(
expected,
VarInt::sint64z(case).fill_bytes(&mut [0; 10]),
"{}",
case
);
}
}
}