#![doc = include_str!("../README.md")]
use std::fmt::Debug;
mod varint;
pub use varint::v64;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Error {
BufferTooShort {
required: usize,
had: usize,
},
VarintOverflow {
bytes: usize,
},
UnsignedOverflow {
value: u64,
},
SignedOverflow {
value: i64,
},
TagTooLarge {
tag: u64,
},
UnknownDiscriminant {
discriminant: u32,
},
NotAChar {
value: u32,
},
}
impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::BufferTooShort { required, had } => fmt
.debug_struct("BufferTooShort")
.field("required", required)
.field("had", had)
.finish(),
Error::VarintOverflow { bytes } => fmt
.debug_struct("VarintOverflow")
.field("bytes", bytes)
.finish(),
Error::UnsignedOverflow { value } => fmt
.debug_struct("UnsignedOverflow")
.field("value", value)
.finish(),
Error::SignedOverflow { value } => fmt
.debug_struct("SignedOverflow")
.field("value", value)
.finish(),
Error::TagTooLarge { tag } => {
fmt.debug_struct("TagTooLarge").field("tag", tag).finish()
}
Error::UnknownDiscriminant { discriminant } => fmt
.debug_struct("UnknownDiscriminant")
.field("discriminant", discriminant)
.finish(),
Error::NotAChar { value } => {
fmt.debug_struct("NotAChar").field("value", value).finish()
}
}
}
}
pub trait Packable {
fn pack_sz(&self) -> usize;
fn pack(&self, out: &mut [u8]);
fn stream<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error>
where
Self: std::marker::Sized,
for<'a> &'a Self: Packable,
{
let pa = stack_pack(self);
let vec: Vec<u8> = pa.to_vec();
match writer.write_all(&vec) {
Ok(_) => Ok(vec.len()),
Err(x) => Err(x),
}
}
}
pub trait Unpackable<'a>: Sized {
type Error: Debug;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Self::Error>;
}
pub fn pack_helper<T: Packable>(t: T, buf: &mut [u8]) -> &mut [u8] {
let sz: usize = t.pack_sz();
assert!(sz <= buf.len(), "packers should never be given short space");
t.pack(&mut buf[..sz]);
&mut buf[sz..]
}
const EMPTY: () = ();
pub fn stack_pack<'a, T: Packable + 'a>(t: T) -> StackPacker<'a, (), T> {
StackPacker { prefix: &EMPTY, t }
}
pub struct StackPacker<'a, P, T>
where
P: Packable + 'a,
T: Packable + 'a,
{
prefix: &'a P,
t: T,
}
impl<'a, P, T> StackPacker<'a, P, T>
where
P: Packable + 'a,
T: Packable + 'a,
{
pub fn pack<'b, U: Packable + 'b>(&'b self, u: U) -> StackPacker<'b, Self, U> {
StackPacker { prefix: self, t: u }
}
pub fn into_slice<'b>(&self, buf: &'b mut [u8]) -> &'b mut [u8] {
let len = self.pack_sz();
assert!(buf.len() >= len);
let buf = &mut buf[0..len];
Packable::pack(self, buf);
buf
}
pub fn to_vec(&self) -> Vec<u8> {
let len = self.pack_sz();
let mut buf = vec![0u8; len];
Packable::pack(self, &mut buf);
buf
}
pub fn append_to_vec(&self, v: &mut Vec<u8>) {
let len = self.pack_sz();
let v_sz = v.len();
v.resize(v_sz + len, 0);
Packable::pack(self, &mut v[v_sz..]);
}
pub fn length_prefixed(&'a self) -> LengthPrefixer<'a, StackPacker<'a, P, T>> {
LengthPrefixer {
size: self.pack_sz(),
body: self,
}
}
}
impl<'a, P, T> Packable for StackPacker<'a, P, T>
where
P: Packable + 'a,
T: Packable + 'a,
{
fn pack_sz(&self) -> usize {
self.prefix.pack_sz() + self.t.pack_sz()
}
fn pack(&self, out: &mut [u8]) {
let (prefix, suffix): (&mut [u8], &mut [u8]) = out.split_at_mut(self.prefix.pack_sz());
self.prefix.pack(prefix);
self.t.pack(suffix);
}
}
#[derive(Clone, Default)]
pub struct Unpacker<'a> {
buf: &'a [u8],
}
impl<'a> Unpacker<'a> {
pub fn new(buf: &'a [u8]) -> Self {
Self { buf }
}
pub fn unpack<'b, E, T: Unpackable<'b, Error = E>>(&mut self) -> Result<T, E>
where
'a: 'b,
{
let (t, buf): (T, &'a [u8]) = Unpackable::unpack(self.buf)?;
self.buf = buf;
Ok(t)
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn remain(&self) -> &'a [u8] {
self.buf
}
pub fn advance(&mut self, by: usize) {
if by > self.buf.len() {
self.buf = &[];
} else {
self.buf = &self.buf[by..];
}
}
}
impl<P: Packable> Packable for &P {
fn pack_sz(&self) -> usize {
(*self).pack_sz()
}
fn pack(&self, out: &mut [u8]) {
(*self).pack(out)
}
}
macro_rules! packable_with_to_le_bytes {
($what:ty) => {
impl Packable for $what {
fn pack_sz(&self) -> usize {
self.to_le_bytes().len()
}
fn pack(&self, out: &mut [u8]) {
let b = &self.to_le_bytes();
assert_eq!(b.len(), out.len());
out.copy_from_slice(b);
}
}
impl<'a> Unpackable<'a> for $what {
type Error = Error;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Error> {
const SZ: usize = std::mem::size_of::<$what>();
if buf.len() >= SZ {
let mut fbuf: [u8; SZ] = [0; SZ];
fbuf.copy_from_slice(&buf[0..SZ]);
Ok((<$what>::from_le_bytes(fbuf), &buf[SZ..]))
} else {
Err(Error::BufferTooShort {
required: SZ,
had: buf.len(),
})
}
}
}
};
}
packable_with_to_le_bytes!(i8);
packable_with_to_le_bytes!(u8);
packable_with_to_le_bytes!(i16);
packable_with_to_le_bytes!(u16);
packable_with_to_le_bytes!(i32);
packable_with_to_le_bytes!(u32);
packable_with_to_le_bytes!(i64);
packable_with_to_le_bytes!(u64);
macro_rules! packable_with_to_bits_to_le_bytes {
($what:ty, $indirect:ty) => {
impl Packable for $what {
fn pack_sz(&self) -> usize {
self.to_bits().to_le_bytes().len()
}
fn pack(&self, out: &mut [u8]) {
let b = &self.to_bits().to_le_bytes();
assert_eq!(b.len(), out.len());
out.copy_from_slice(b);
}
}
impl<'a> Unpackable<'a> for $what {
type Error = Error;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Error> {
const SZ: usize = std::mem::size_of::<$what>();
if buf.len() >= SZ {
let mut fbuf: [u8; SZ] = [0; SZ];
fbuf.copy_from_slice(&buf[0..SZ]);
Ok((
<$what>::from_bits(<$indirect>::from_le_bytes(fbuf)),
&buf[SZ..],
))
} else {
Err(Error::BufferTooShort {
required: SZ,
had: buf.len(),
})
}
}
}
};
}
packable_with_to_bits_to_le_bytes!(f32, u32);
packable_with_to_bits_to_le_bytes!(f64, u64);
impl Packable for char {
fn pack_sz(&self) -> usize {
(*self as u32).pack_sz()
}
fn pack(&self, out: &mut [u8]) {
(*self as u32).pack(out)
}
}
impl<'a> Unpackable<'a> for char {
type Error = Error;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(char, &'b [u8]), Error> {
let (c, buf) = u32::unpack(buf)?;
if let Some(c) = char::from_u32(c) {
Ok((c, buf))
} else {
Err(Error::NotAChar { value: c })
}
}
}
pub fn length_free<P: Packable>(slice: &[P]) -> LengthFree<P> {
LengthFree { slice }
}
pub struct LengthFree<'a, P: Packable> {
slice: &'a [P],
}
impl<'a, P: Packable> Packable for LengthFree<'a, P> {
fn pack_sz(&self) -> usize {
self.slice.iter().map(|x| x.pack_sz()).sum()
}
fn pack(&self, out: &mut [u8]) {
let mut out = out;
for i in 0..self.slice.len() {
out = pack_helper(&self.slice[i], out);
}
}
}
pub struct LengthPrefixer<'a, P>
where
P: Packable + 'a,
{
size: usize,
body: &'a P,
}
impl<'a, P> Packable for LengthPrefixer<'a, P>
where
P: Packable + 'a,
{
fn pack_sz(&self) -> usize {
let vsz: v64 = self.size.into();
vsz.pack_sz() + self.size
}
fn pack(&self, out: &mut [u8]) {
let vsz: v64 = self.size.into();
let (prefix, suffix): (&mut [u8], &mut [u8]) = out.split_at_mut(vsz.pack_sz());
vsz.pack(prefix);
self.body.pack(suffix);
}
}
impl Packable for &[u8] {
fn pack_sz(&self) -> usize {
let vsz: v64 = self.len().into();
vsz.pack_sz() + self.len()
}
fn pack(&self, out: &mut [u8]) {
let vsz: v64 = self.len().into();
let (prefix, suffix): (&mut [u8], &mut [u8]) = out.split_at_mut(vsz.pack_sz());
vsz.pack(prefix);
suffix.copy_from_slice(self);
}
}
impl<'a> Unpackable<'a> for &'a [u8] {
type Error = Error;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Error> {
let (vsz, buf): (v64, &'b [u8]) = v64::unpack(buf)?;
let x: usize = vsz.into();
if x > buf.len() {
Err(Error::BufferTooShort {
required: x,
had: buf.len(),
})
} else {
Ok((&buf[0..x], &buf[x..]))
}
}
}
macro_rules! impl_pack_unpack_tuple {
() => {
impl Packable for () {
fn pack_sz(&self) -> usize {
0
}
fn pack(&self, _: &mut [u8]) {}
}
impl<'a> Unpackable<'a> for () {
type Error = Error;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Error> {
Ok(((), buf))
}
}
};
( $($name:ident)+ ) => {
#[allow(non_snake_case)]
impl<$($name: Packable),+> Packable for ($($name,)+) {
fn pack_sz(&self) -> usize {
let ($(ref $name,)+) = *self;
$($name.pack_sz() + )+ 0
}
fn pack(&self, buf: &mut[u8]) {
let ($(ref $name,)+) = *self;
let pa = stack_pack(());
$(let pa = pa.pack($name);)+
pa.into_slice(buf);
}
}
#[allow(non_snake_case)]
impl<'a, ER: Debug, $($name: Unpackable<'a, Error=ER> + 'a),+> Unpackable<'a> for ($($name,)+) {
type Error = ER;
fn unpack<'b: 'a>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Self::Error> {
let mut up: Unpacker<'b> = Unpacker::new(buf);
$(let $name = up.unpack()?;)+
let rem: &'b [u8] = up.remain();
Ok((($($name,)+), rem))
}
}
};
}
impl_pack_unpack_tuple! {}
impl_pack_unpack_tuple! { A }
impl_pack_unpack_tuple! { A B }
impl_pack_unpack_tuple! { A B C }
impl_pack_unpack_tuple! { A B C D }
impl_pack_unpack_tuple! { A B C D E }
impl_pack_unpack_tuple! { A B C D E F }
impl_pack_unpack_tuple! { A B C D E F G }
impl_pack_unpack_tuple! { A B C D E F G H }
impl_pack_unpack_tuple! { A B C D E F G H I }
impl_pack_unpack_tuple! { A B C D E F G H I J }
impl_pack_unpack_tuple! { A B C D E F G H I J K }
impl_pack_unpack_tuple! { A B C D E F G H I J K L }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U V }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X Y }
impl_pack_unpack_tuple! { A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }
impl<T: Packable, E: Packable> Packable for Result<T, E> {
fn pack_sz(&self) -> usize {
match self {
Ok(x) => stack_pack(v64::from(10))
.pack(v64::from(x.pack_sz()))
.pack(x)
.pack_sz(),
Err(e) => stack_pack(v64::from(18))
.pack(v64::from(e.pack_sz()))
.pack(e)
.pack_sz(),
}
}
fn pack(&self, out: &mut [u8]) {
match self {
Ok(x) => {
stack_pack(v64::from(10))
.pack(v64::from(x.pack_sz()))
.pack(x)
.into_slice(out);
}
Err(e) => {
stack_pack(v64::from(18))
.pack(v64::from(e.pack_sz()))
.pack(e)
.into_slice(out);
}
}
}
}
impl<'a, T, E> Unpackable<'a> for Result<T, E>
where
T: Unpackable<'a>,
E: Unpackable<'a>
+ Debug
+ From<Error>
+ From<<T as Unpackable<'a>>::Error>
+ From<<E as Unpackable<'a>>::Error>,
{
type Error = E;
fn unpack<'b>(buf: &'b [u8]) -> Result<(Self, &'b [u8]), Self::Error>
where
'b: 'a,
{
let mut up = Unpacker::new(buf);
let tag: v64 = up.unpack()?;
if <v64 as Into<u64>>::into(tag) > u32::max_value() as u64 {
return Err(Error::TagTooLarge { tag: tag.into() }.into());
}
let tag: u32 = tag.try_into().unwrap();
match tag {
10 => {
let x: v64 = up.unpack()?;
let buf: &[u8] = &up.remain()[..x.into()];
up.advance(x.into());
let (t, _): (T, _) = <T as Unpackable>::unpack(buf)?;
Ok((Ok(t), up.remain()))
}
18 => {
let x: v64 = up.unpack()?;
let buf: &[u8] = &up.remain()[..x.into()];
up.advance(x.into());
let (e, _): (E, _) = <E as Unpackable>::unpack(buf)?;
Ok((Err(e), up.remain()))
}
_ => Err(Error::UnknownDiscriminant { discriminant: tag }.into()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pack_void() {
let buf: &mut [u8; 0] = &mut [];
().pack(buf);
let mut up = Unpacker::new(buf);
let x: Result<(), Error> = up.unpack();
assert_eq!(Ok(()), x, "human got decode wrong?");
assert_eq!(0, up.buf.len(), "human got remainder wrong?");
}
macro_rules! test_pack_with_to_le_bytes {
($what:ty, $num:expr, $x:expr, $human:expr) => {{
const HUMAN: &[u8] = $human;
const X: $what = $x as $what;
const LEN: usize = $num;
let exp = &X.to_le_bytes();
assert_eq!(HUMAN, exp, "human got test vector wrong?");
assert_eq!(LEN, exp.len(), "human got test vector wrong?");
{
let buf: &mut [u8; LEN] = &mut <[u8; LEN]>::default();
X.pack(buf);
assert_eq!(exp, buf, "human got implementation wrong?");
assert_eq!(HUMAN, buf, "human got test macro wrong?");
}
{
let mut up = Unpacker::new(HUMAN);
let x = up.unpack();
let expect: Result<$what, Error> = Ok(X);
assert_eq!(expect, x, "human got implementation wrong?");
assert_eq!(0, up.buf.len(), "human got remainder wrong?");
}
}};
}
#[test]
fn pack_and_unpack_integers() {
test_pack_with_to_le_bytes!(u8, 1, 0xc0u8, &[0xc0]);
test_pack_with_to_le_bytes!(i8, 1, 0xc0u8, &[0xc0]);
test_pack_with_to_le_bytes!(u16, 2, 0xc0ffu16, &[0xff, 0xc0]);
test_pack_with_to_le_bytes!(i16, 2, 0xc0ffu16, &[0xff, 0xc0]);
test_pack_with_to_le_bytes!(i32, 4, 0xc0ffeedau32, &[0xda, 0xee, 0xff, 0xc0]);
test_pack_with_to_le_bytes!(u32, 4, 0xc0ffeedau32, &[0xda, 0xee, 0xff, 0xc0]);
test_pack_with_to_le_bytes!(
i64,
8,
0xc0ffeeda7e11f00du64,
&[0x0d, 0xf0, 0x11, 0x7e, 0xda, 0xee, 0xff, 0xc0]
);
test_pack_with_to_le_bytes!(
u64,
8,
0xc0ffeeda7e11f00du64,
&[0x0d, 0xf0, 0x11, 0x7e, 0xda, 0xee, 0xff, 0xc0]
);
}
macro_rules! test_pack_with_to_bits_to_le_bytes {
($what:ty, $num:expr, $x:expr, $human:expr) => {{
const HUMAN: &[u8] = $human;
const X: $what = $x as $what;
const LEN: usize = $num;
let exp = &X.to_bits().to_le_bytes();
assert_eq!(HUMAN, exp, "human got test vector wrong?");
assert_eq!(LEN, exp.len(), "human got test vector wrong?");
{
let buf: &mut [u8; LEN] = &mut <[u8; LEN]>::default();
X.pack(buf);
assert_eq!(exp, buf, "human got implementation wrong?");
assert_eq!(HUMAN, buf, "human got test macro wrong?");
}
{
let mut up = Unpacker::new(HUMAN);
let x = up.unpack();
let expect: Result<$what, Error> = Ok(X);
assert_eq!(expect, x, "human got implementation wrong?");
assert_eq!(0, up.buf.len(), "human got remainder wrong?");
}
}};
}
#[test]
fn pack_and_unpack_floats() {
test_pack_with_to_bits_to_le_bytes!(f32, 4, 16711938.0, &[0x02, 0x01, 0x7f, 0x4b]);
test_pack_with_to_bits_to_le_bytes!(
f64,
8,
9006104071832581.0,
&[0x05, 0x04, 0x03, 0x02, 0x01, 0xff, 0x3f, 0x43]
);
}
#[test]
fn split_tuple() {
let (a, b, c, d) = (42u8, 13u8, 73u8, 32u8);
let mut buf = [0u8; 4];
(a, b, c, d).pack(&mut buf);
assert_eq!([a, b, c, d], buf, "human got serialization wrong?");
let mut up = Unpacker::new(&buf);
let (ap, bp): (u8, u8) = up.unpack().unwrap();
let (cp, dp): (u8, u8) = up.unpack().unwrap();
assert_eq!(
[a, b, c, d],
[ap, bp, cp, dp],
"human got deserialization wrong?"
);
}
#[test]
fn length_free() {
let buf = &mut [0u8; 64];
let buf = stack_pack(super::length_free(&[0u8, 1u8, 2u8])).into_slice(buf);
assert_eq!([0, 1, 2], buf, "human got length_free wrong?");
}
#[test]
fn stack_pack_into_slice() {
let buf = &mut [0u8; 64];
let buf = stack_pack(42u64).into_slice(buf);
assert_eq!(
&[42, 0, 0, 0, 0, 0, 0, 0],
buf,
"human got into_slice wrong?"
);
}
#[test]
fn stack_pack_to_vec() {
let buf: &[u8] = &stack_pack(42u64).to_vec();
assert_eq!(&[42, 0, 0, 0, 0, 0, 0, 0], &buf, "human got to_vec wrong?");
}
#[test]
fn stack_packer() {
let pa = stack_pack(());
let pa = pa.pack(1u8);
let pa = pa.pack(770u16);
let pa = pa.pack(117835012u32);
let pa = pa.pack(1084818905618843912u64);
let mut buf = [0u8; 16];
let buf = pa.into_slice(&mut buf);
assert_eq!([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], buf);
}
#[test]
fn unpacker() {
let buf: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut up = Unpacker::new(buf);
let x = up.unpack::<Error, ()>();
assert_eq!(Ok(()), x, "human got () unpacker wrong?");
let x = up.unpack::<Error, u8>();
assert_eq!(Ok(1u8), x, "human got u8 unpacker wrong?");
let x = up.unpack::<Error, u16>();
assert_eq!(Ok(770u16), x, "human got u16 unpacker wrong?");
let x = up.unpack::<Error, u32>();
assert_eq!(Ok(117835012u32), x, "human got u32 unpacker wrong?");
let x = up.unpack::<Error, u64>();
assert_eq!(
Ok(1084818905618843912u64),
x,
"human got u64 unpacker wrong?"
);
assert_eq!(&[] as &[u8], up.buf, "human got remaining buffer wrong?");
}
#[test]
fn pack_and_unpack_slice() {
let buf: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let pa = stack_pack(buf);
let exp: &[u8] = &[16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let got: &[u8] = &pa.to_vec();
assert_eq!(exp, got);
let mut up = Unpacker::new(exp);
let got: &[u8] = up.unpack().expect("unpack slice");
assert_eq!(buf, got);
}
}