pub use autocodec_derive::Codec;
use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CodecError {
NotEnoughBytes { needed: usize, available: usize },
InvalidUtf8,
UnknownDiscriminant { value: u8 },
TooShort { min: usize, actual: usize },
TooLong { max: usize, actual: usize },
BadMagic,
ValidationFailed,
TrailingBytes { count: usize },
AllocationTooLarge { requested: usize },
FieldError { field: &'static str, source: Box<CodecError> },
}
pub const MAX_DECODE_LEN: usize = 16 * 1024 * 1024;
impl core::fmt::Display for CodecError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::NotEnoughBytes { needed, available } => {
write!(f, "not enough bytes: needed {needed}, have {available}")
}
Self::InvalidUtf8 => write!(f, "invalid UTF-8"),
Self::UnknownDiscriminant { value } => {
write!(f, "unknown discriminant: {value}")
}
Self::TooShort { min, actual } => {
write!(f, "length too short: minimum {min}, got {actual}")
}
Self::TooLong { max, actual } => {
write!(f, "length too long: maximum {max}, got {actual}")
}
Self::BadMagic => write!(f, "magic value mismatch"),
Self::ValidationFailed => write!(f, "validation failed"),
Self::TrailingBytes { count } => {
write!(f, "trailing bytes: {count} unexpected bytes after decode")
}
Self::AllocationTooLarge { requested } => {
write!(f, "allocation too large: {requested} elements requested")
}
Self::FieldError { field, source } => {
write!(f, "in field `{field}`: {source}")
}
}
}
}
impl std::error::Error for CodecError {}
pub trait Codec: Sized {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError>;
fn encode(&self, buf: &mut Vec<u8>);
fn encoded_size(&self) -> usize {
let mut buf = Vec::new();
self.encode(&mut buf);
buf.len()
}
fn decode_exact(input: &[u8]) -> Result<Self, CodecError> {
let (val, rest) = Self::decode(input)?;
if !rest.is_empty() {
return Err(CodecError::TrailingBytes { count: rest.len() });
}
Ok(val)
}
}
#[doc(hidden)]
#[inline]
pub fn check_len(input: &[u8], n: usize) -> Result<(), CodecError> {
if input.len() < n {
Err(CodecError::NotEnoughBytes { needed: n, available: input.len() })
} else {
Ok(())
}
}
#[inline]
fn check(input: &[u8], n: usize) -> Result<(), CodecError> {
check_len(input, n)
}
macro_rules! impl_int {
($($t:ty),*) => {$(
impl Codec for $t {
#[inline]
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
const N: usize = core::mem::size_of::<$t>();
check(input, N)?;
let val = <$t>::from_be_bytes(input[..N].try_into().unwrap());
Ok((val, &input[N..]))
}
#[inline]
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.to_be_bytes());
}
#[inline]
fn encoded_size(&self) -> usize { core::mem::size_of::<$t>() }
}
)*};
}
impl_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
impl Codec for f32 {
#[inline]
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
check(input, 4)?;
let val = f32::from_be_bytes(input[..4].try_into().unwrap());
Ok((val, &input[4..]))
}
#[inline]
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.to_be_bytes());
}
#[inline]
fn encoded_size(&self) -> usize { 4 }
}
impl Codec for f64 {
#[inline]
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
check(input, 8)?;
let val = f64::from_be_bytes(input[..8].try_into().unwrap());
Ok((val, &input[8..]))
}
#[inline]
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.to_be_bytes());
}
#[inline]
fn encoded_size(&self) -> usize { 8 }
}
#[doc(hidden)]
pub trait CodecBe: Sized {
fn decode_be(input: &[u8]) -> Result<(Self, &[u8]), CodecError>;
fn encode_be(&self, buf: &mut Vec<u8>);
}
#[doc(hidden)]
pub trait CodecLe: Sized {
fn decode_le(input: &[u8]) -> Result<(Self, &[u8]), CodecError>;
fn encode_le(&self, buf: &mut Vec<u8>);
}
macro_rules! impl_endian {
($($t:ty),*) => {$(
impl CodecBe for $t {
#[inline]
fn decode_be(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
const N: usize = core::mem::size_of::<$t>();
check(input, N)?;
Ok((<$t>::from_be_bytes(input[..N].try_into().unwrap()), &input[N..]))
}
#[inline]
fn encode_be(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.to_be_bytes());
}
}
impl CodecLe for $t {
#[inline]
fn decode_le(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
const N: usize = core::mem::size_of::<$t>();
check(input, N)?;
Ok((<$t>::from_le_bytes(input[..N].try_into().unwrap()), &input[N..]))
}
#[inline]
fn encode_le(&self, buf: &mut Vec<u8>) {
buf.extend_from_slice(&self.to_le_bytes());
}
}
)*};
}
impl_endian!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
#[doc(hidden)]
#[inline]
pub fn decode_be<T: CodecBe>(input: &[u8]) -> Result<(T, &[u8]), CodecError> { T::decode_be(input) }
#[doc(hidden)]
#[inline]
pub fn encode_be<T: CodecBe>(val: &T, buf: &mut Vec<u8>) { val.encode_be(buf); }
#[doc(hidden)]
#[inline]
pub fn decode_le<T: CodecLe>(input: &[u8]) -> Result<(T, &[u8]), CodecError> { T::decode_le(input) }
#[doc(hidden)]
#[inline]
pub fn encode_le<T: CodecLe>(val: &T, buf: &mut Vec<u8>) { val.encode_le(buf); }
#[doc(hidden)]
pub trait LenPrefix: Codec {
fn to_usize(self) -> usize;
fn from_usize(n: usize) -> Self;
}
impl LenPrefix for u8 {
#[inline] fn to_usize(self) -> usize { self as usize }
#[inline] fn from_usize(n: usize) -> Self { n as u8 }
}
impl LenPrefix for u16 {
#[inline] fn to_usize(self) -> usize { self as usize }
#[inline] fn from_usize(n: usize) -> Self { n as u16 }
}
impl LenPrefix for u32 {
#[inline] fn to_usize(self) -> usize { self as usize }
#[inline] fn from_usize(n: usize) -> Self { n as u32 }
}
impl LenPrefix for u64 {
#[inline] fn to_usize(self) -> usize { self as usize }
#[inline] fn from_usize(n: usize) -> Self { n as u64 }
}
#[doc(hidden)]
pub trait CodecWithLen: Sized {
fn decode_with_len<L: LenPrefix>(input: &[u8]) -> Result<(Self, &[u8]), CodecError>;
fn encode_with_len<L: LenPrefix>(&self, buf: &mut Vec<u8>);
}
impl<T: Codec> CodecWithLen for Vec<T> {
fn decode_with_len<L: LenPrefix>(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (len, mut rest) = L::decode(input)?;
let count = len.to_usize();
if count > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: count });
}
let mut vec = Vec::with_capacity(count.min(rest.len()));
for _ in 0..count {
let (item, remaining) = T::decode(rest)?;
vec.push(item);
rest = remaining;
}
Ok((vec, rest))
}
fn encode_with_len<L: LenPrefix>(&self, buf: &mut Vec<u8>) {
L::from_usize(self.len()).encode(buf);
for item in self { item.encode(buf); }
}
}
impl CodecWithLen for String {
fn decode_with_len<L: LenPrefix>(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (len, rest) = L::decode(input)?;
let n = len.to_usize();
if n > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: n });
}
check(rest, n)?;
let s = String::from_utf8(rest[..n].to_vec()).map_err(|_| CodecError::InvalidUtf8)?;
Ok((s, &rest[n..]))
}
fn encode_with_len<L: LenPrefix>(&self, buf: &mut Vec<u8>) {
L::from_usize(self.len()).encode(buf);
buf.extend_from_slice(self.as_bytes());
}
}
impl<T: Codec> CodecWithLen for Box<[T]> {
fn decode_with_len<L: LenPrefix>(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (vec, rest) = <Vec<T> as CodecWithLen>::decode_with_len::<L>(input)?;
Ok((vec.into_boxed_slice(), rest))
}
fn encode_with_len<L: LenPrefix>(&self, buf: &mut Vec<u8>) {
L::from_usize(self.len()).encode(buf);
for item in self.iter() { item.encode(buf); }
}
}
#[doc(hidden)]
#[inline]
pub fn decode_with_len<L: LenPrefix, T: CodecWithLen>(input: &[u8]) -> Result<(T, &[u8]), CodecError> {
T::decode_with_len::<L>(input)
}
#[doc(hidden)]
#[inline]
pub fn encode_with_len<L: LenPrefix, T: CodecWithLen>(val: &T, buf: &mut Vec<u8>) {
val.encode_with_len::<L>(buf);
}
#[doc(hidden)]
pub trait HasLen {
fn codec_len(&self) -> usize;
}
impl<T> HasLen for Vec<T> {
#[inline] fn codec_len(&self) -> usize { self.len() }
}
impl HasLen for String {
#[inline] fn codec_len(&self) -> usize { self.len() }
}
impl<T> HasLen for Box<[T]> {
#[inline] fn codec_len(&self) -> usize { self.len() }
}
#[doc(hidden)]
#[inline]
pub fn check_min_len<T: HasLen>(val: &T, min: usize) -> Result<(), CodecError> {
let actual = val.codec_len();
if actual < min { Err(CodecError::TooShort { min, actual }) } else { Ok(()) }
}
#[doc(hidden)]
#[inline]
pub fn check_max_len<T: HasLen>(val: &T, max: usize) -> Result<(), CodecError> {
let actual = val.codec_len();
if actual > max { Err(CodecError::TooLong { max, actual }) } else { Ok(()) }
}
#[doc(hidden)]
#[inline]
pub fn field_err(field: &'static str, e: CodecError) -> CodecError {
CodecError::FieldError { field, source: Box::new(e) }
}
#[doc(hidden)]
#[inline]
pub fn skip_decode<T: Default>() -> T { T::default() }
#[doc(hidden)]
#[inline]
pub fn decode_padding(input: &[u8], n: usize) -> Result<&[u8], CodecError> {
check(input, n)?;
Ok(&input[n..])
}
#[doc(hidden)]
#[inline]
pub fn encode_padding(buf: &mut Vec<u8>, n: usize) {
buf.extend(std::iter::repeat_n(0u8, n));
}
#[doc(hidden)]
pub fn decode_magic_u8(input: &[u8], expected: u8) -> Result<&[u8], CodecError> {
let (val, rest) = u8::decode(input)?;
if val != expected { return Err(CodecError::BadMagic); }
Ok(rest)
}
#[doc(hidden)]
pub fn decode_magic_u16(input: &[u8], expected: u16) -> Result<&[u8], CodecError> {
let (val, rest) = u16::decode(input)?;
if val != expected { return Err(CodecError::BadMagic); }
Ok(rest)
}
#[doc(hidden)]
pub fn decode_magic_u32(input: &[u8], expected: u32) -> Result<&[u8], CodecError> {
let (val, rest) = u32::decode(input)?;
if val != expected { return Err(CodecError::BadMagic); }
Ok(rest)
}
#[doc(hidden)]
pub fn decode_magic_u64(input: &[u8], expected: u64) -> Result<&[u8], CodecError> {
let (val, rest) = u64::decode(input)?;
if val != expected { return Err(CodecError::BadMagic); }
Ok(rest)
}
#[doc(hidden)]
#[inline]
pub fn extract_bits(bytes: &[u8], bit_offset: usize, bits: usize) -> u64 {
let byte_start = bit_offset / 8;
let byte_end = (bit_offset + bits).div_ceil(8);
let n = byte_end - byte_start;
let mut raw: u64 = 0;
for i in 0..n {
raw = (raw << 8) | bytes[byte_start + i] as u64;
}
let shift = n * 8 - (bit_offset % 8) - bits;
let mask = (1u64 << bits) - 1;
(raw >> shift) & mask
}
#[doc(hidden)]
#[inline]
pub fn set_bits(bytes: &mut [u8], bit_offset: usize, bits: usize, val: u64) {
let byte_start = bit_offset / 8;
let byte_end = (bit_offset + bits).div_ceil(8);
let n = byte_end - byte_start;
let mut raw: u64 = 0;
for i in 0..n {
raw = (raw << 8) | bytes[byte_start + i] as u64;
}
let shift = n * 8 - (bit_offset % 8) - bits;
let mask = (1u64 << bits) - 1;
raw &= !(mask << shift);
raw |= (val & mask) << shift;
for i in (0..n).rev() {
bytes[byte_start + i] = (raw & 0xFF) as u8;
raw >>= 8;
}
}
impl Codec for bool {
#[inline]
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (b, rest) = u8::decode(input)?;
Ok((b != 0, rest))
}
#[inline]
fn encode(&self, buf: &mut Vec<u8>) {
buf.push(if *self { 1 } else { 0 });
}
#[inline]
fn encoded_size(&self) -> usize { 1 }
}
impl<T: Codec> Codec for Vec<T> {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (len, mut rest) = u32::decode(input)?;
let count = len as usize;
if count > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: count });
}
let mut vec = Vec::with_capacity(count.min(rest.len()));
for _ in 0..count {
let (item, remaining) = T::decode(rest)?;
vec.push(item);
rest = remaining;
}
Ok((vec, rest))
}
fn encode(&self, buf: &mut Vec<u8>) {
(self.len() as u32).encode(buf);
for item in self { item.encode(buf); }
}
fn encoded_size(&self) -> usize {
4 + self.iter().map(|i| i.encoded_size()).sum::<usize>()
}
}
impl Codec for String {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (len, rest) = u32::decode(input)?;
let n = len as usize;
if n > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: n });
}
check(rest, n)?;
let s = String::from_utf8(rest[..n].to_vec()).map_err(|_| CodecError::InvalidUtf8)?;
Ok((s, &rest[n..]))
}
fn encode(&self, buf: &mut Vec<u8>) {
(self.len() as u32).encode(buf);
buf.extend_from_slice(self.as_bytes());
}
fn encoded_size(&self) -> usize { 4 + self.len() }
}
impl<T: Codec> Codec for Option<T> {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (tag, rest) = u8::decode(input)?;
match tag {
0 => Ok((None, rest)),
_ => { let (val, rest) = T::decode(rest)?; Ok((Some(val), rest)) }
}
}
fn encode(&self, buf: &mut Vec<u8>) {
match self {
None => 0u8.encode(buf),
Some(val) => { 1u8.encode(buf); val.encode(buf); }
}
}
fn encoded_size(&self) -> usize {
1 + match self { None => 0, Some(val) => val.encoded_size() }
}
}
impl<T: Codec> Codec for Box<T> {
#[inline]
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (val, rest) = T::decode(input)?;
Ok((Box::new(val), rest))
}
#[inline]
fn encode(&self, buf: &mut Vec<u8>) {
(**self).encode(buf);
}
#[inline]
fn encoded_size(&self) -> usize { (**self).encoded_size() }
}
impl<T: Codec> Codec for Box<[T]> {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (vec, rest) = Vec::<T>::decode(input)?;
Ok((vec.into_boxed_slice(), rest))
}
fn encode(&self, buf: &mut Vec<u8>) {
(self.len() as u32).encode(buf);
for item in self.iter() { item.encode(buf); }
}
fn encoded_size(&self) -> usize {
4 + self.iter().map(|i| i.encoded_size()).sum::<usize>()
}
}
impl<K: Codec + Eq + Hash, V: Codec> Codec for HashMap<K, V> {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let (len, mut rest) = u32::decode(input)?;
let mut map = HashMap::with_capacity(len as usize);
for _ in 0..len {
let (k, remaining) = K::decode(rest)?;
let (v, remaining) = V::decode(remaining)?;
map.insert(k, v);
rest = remaining;
}
Ok((map, rest))
}
fn encode(&self, buf: &mut Vec<u8>) {
(self.len() as u32).encode(buf);
for (k, v) in self { k.encode(buf); v.encode(buf); }
}
fn encoded_size(&self) -> usize {
4 + self.iter().map(|(k, v)| k.encoded_size() + v.encoded_size()).sum::<usize>()
}
}
impl<T: Codec, const N: usize> Codec for [T; N] {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
let mut rest = input;
let mut vec = Vec::with_capacity(N);
for _ in 0..N {
let (val, remaining) = T::decode(rest)?;
vec.push(val);
rest = remaining;
}
let arr: [T; N] = match vec.try_into() {
Ok(a) => a,
Err(_) => unreachable!(),
};
Ok((arr, rest))
}
fn encode(&self, buf: &mut Vec<u8>) {
for item in self { item.encode(buf); }
}
fn encoded_size(&self) -> usize {
self.iter().map(|i| i.encoded_size()).sum()
}
}
macro_rules! impl_tuple {
($($idx:tt $T:ident),+) => {
#[allow(non_snake_case)]
impl<$($T: Codec),+> Codec for ($($T,)+) {
fn decode(input: &[u8]) -> Result<(Self, &[u8]), CodecError> {
$(let ($T, input) = $T::decode(input)?;)+
Ok((($($T,)+), input))
}
fn encode(&self, buf: &mut Vec<u8>) {
$(self.$idx.encode(buf);)+
}
fn encoded_size(&self) -> usize {
0 $(+ self.$idx.encoded_size())+
}
}
};
}
impl_tuple!(0 A);
impl_tuple!(0 A, 1 B);
impl_tuple!(0 A, 1 B, 2 C);
impl_tuple!(0 A, 1 B, 2 C, 3 D);
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E);
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F);
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G);
impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Bytes<'a>(pub &'a [u8]);
impl<'a> Bytes<'a> {
pub fn decode(input: &'a [u8]) -> Result<(Self, &'a [u8]), CodecError> {
let (len, rest) = u32::decode(input)?;
let n = len as usize;
if n > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: n });
}
check(rest, n)?;
Ok((Bytes(&rest[..n]), &rest[n..]))
}
pub fn decode_with_len<L: LenPrefix>(input: &'a [u8]) -> Result<(Self, &'a [u8]), CodecError> {
let (len, rest) = L::decode(input)?;
let n = len.to_usize();
if n > MAX_DECODE_LEN {
return Err(CodecError::AllocationTooLarge { requested: n });
}
check(rest, n)?;
Ok((Bytes(&rest[..n]), &rest[n..]))
}
pub fn encode(&self, buf: &mut Vec<u8>) {
(self.0.len() as u32).encode(buf);
buf.extend_from_slice(self.0);
}
pub fn encoded_size(&self) -> usize { 4 + self.0.len() }
}
impl<'a> AsRef<[u8]> for Bytes<'a> {
fn as_ref(&self) -> &[u8] { self.0 }
}
impl<'a> core::ops::Deref for Bytes<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] { self.0 }
}