#![no_std]
#![warn(missing_debug_implementations)]
#![warn(non_ascii_idents)]
#![warn(single_use_lifetimes)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_lifetimes)]
#![warn(unused_qualifications)]
#![warn(variant_size_differences)]
#![warn(clippy::cargo)]
#![warn(clippy::nursery)]
#![warn(clippy::pedantic)]
#![allow(clippy::inline_always)]
#![warn(clippy::assertions_on_result_states)]
#![warn(clippy::clone_on_ref_ptr)]
#![warn(clippy::dbg_macro)]
#![warn(clippy::decimal_literal_representation)]
#![warn(clippy::default_union_representation)]
#![warn(clippy::deref_by_slicing)]
#![warn(clippy::empty_drop)]
#![warn(clippy::empty_structs_with_brackets)]
#![warn(clippy::exhaustive_enums)]
#![warn(clippy::exit)]
#![warn(clippy::fn_to_numeric_cast_any)]
#![warn(clippy::format_push_string)]
#![warn(clippy::get_unwrap)]
#![warn(clippy::if_then_some_else_none)]
#![warn(clippy::lossy_float_literal)]
#![warn(clippy::missing_enforced_import_renames)]
#![warn(clippy::mixed_read_write_in_expression)]
#![warn(clippy::mod_module_files)]
#![warn(clippy::mutex_atomic)]
#![warn(clippy::pattern_type_mismatch)]
#![warn(clippy::print_stdout)]
#![warn(clippy::rc_buffer)]
#![warn(clippy::rc_mutex)]
#![warn(clippy::rest_pat_in_fully_bound_structs)]
#![warn(clippy::str_to_string)]
#![warn(clippy::string_add)]
#![warn(clippy::string_to_string)]
#![warn(clippy::suspicious_xor_used_as_pow)]
#![warn(clippy::todo)]
#![warn(clippy::try_err)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![warn(clippy::unnecessary_safety_comment)]
#![warn(clippy::unnecessary_safety_doc)]
#![warn(clippy::unnecessary_self_imports)]
#![warn(clippy::unneeded_field_pattern)]
#![warn(clippy::unseparated_literal_suffix)]
use core::ops::{Deref, DerefMut};
use core::{mem, ptr, slice};
use smallvec::SmallVec;
const INLINE_CAP: usize = 32;
pub trait Pack {
#[must_use]
fn append(&mut self) -> Packer;
#[must_use]
fn at(&mut self, i: usize) -> Packer;
}
pub trait Unpack {
fn unpack(&self) -> Unpacker;
}
impl<T: AsRef<[u8]>> Unpack for T {
#[inline(always)]
fn unpack(&self) -> Unpacker {
Unpacker::new(self.as_ref())
}
}
#[derive(Clone, Debug, Default)]
#[must_use]
pub struct StructBuf {
lim: usize,
b: SmallVec<[u8; INLINE_CAP]>,
}
impl StructBuf {
#[inline(always)]
pub const fn new(lim: usize) -> Self {
Self {
lim,
b: SmallVec::new_const(),
}
}
#[inline(always)]
pub const fn none() -> Self {
Self::new(0)
}
#[inline(always)]
pub fn with_capacity(cap: usize) -> Self {
Self {
lim: cap,
b: SmallVec::with_capacity(cap),
}
}
#[inline(always)]
#[must_use]
pub fn len(&self) -> usize {
self.b.len()
}
#[inline(always)]
#[must_use]
pub fn capacity(&self) -> usize {
self.b.capacity().min(self.lim)
}
#[inline(always)]
#[must_use]
pub const fn lim(&self) -> usize {
self.lim
}
#[inline(always)]
#[must_use]
pub fn remaining(&self) -> usize {
self.lim - self.b.len()
}
#[inline(always)]
#[must_use]
pub fn is_empty(&self) -> bool {
self.b.is_empty()
}
#[inline(always)]
#[must_use]
pub fn is_full(&self) -> bool {
self.remaining() == 0
}
#[inline(always)]
#[must_use]
pub const fn is_none(&self) -> bool {
self.lim == 0
}
#[inline]
pub fn truncate(&mut self, n: usize) -> &mut Self {
if n < self.b.len() {
unsafe { self.b.set_len(n) }
}
self
}
#[inline(always)]
pub fn clear(&mut self) -> &mut Self {
self.truncate(0)
}
#[inline(always)]
pub fn take(&mut self) -> Self {
mem::replace(self, Self::none())
}
#[inline]
pub unsafe fn set_len(&mut self, n: usize) -> &mut Self {
debug_assert!(n <= self.capacity());
self.b.set_len(n);
self
}
#[inline]
#[must_use]
pub const fn can_put_at(&self, i: usize, n: usize) -> bool {
let (sum, overflow) = i.overflowing_add(n);
sum <= self.lim && !overflow
}
#[inline(always)]
pub fn put_at<T: AsRef<[u8]>>(&mut self, i: usize, v: T) {
assert!(self.try_put_at(i, v), "buffer limit exceeded");
}
#[inline]
pub fn try_put_at<T: AsRef<[u8]>>(&mut self, i: usize, v: T) -> bool {
let v = v.as_ref();
let (j, overflow) = i.overflowing_add(v.len());
let ok = !overflow && j <= self.lim;
if ok {
unsafe { self.put_at_unchecked(i, j, v) };
}
ok
}
unsafe fn put_at_unchecked(&mut self, i: usize, j: usize, v: &[u8]) {
if self.b.capacity() < j {
self.b.grow(self.lim); }
let pad = i.saturating_sub(self.b.len());
let dst = self.b.as_mut_ptr();
if pad > 0 {
unsafe { dst.add(self.b.len()).write_bytes(0, pad) };
}
unsafe { dst.add(i).copy_from_nonoverlapping(v.as_ptr(), v.len()) };
if j > self.b.len() {
unsafe { self.b.set_len(j) };
}
}
}
impl Pack for StructBuf {
#[inline(always)]
fn append(&mut self) -> Packer {
self.at(self.b.len())
}
#[inline(always)]
fn at(&mut self, i: usize) -> Packer {
Packer { i, b: self }
}
}
impl AsRef<[u8]> for StructBuf {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
&self.b
}
}
impl AsMut<[u8]> for StructBuf {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.b
}
}
impl Deref for StructBuf {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.b
}
}
impl DerefMut for StructBuf {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.b
}
}
#[derive(Debug)]
pub struct Packer<'a> {
i: usize,
b: &'a mut StructBuf, }
impl Packer<'_> {
#[inline(always)]
#[must_use]
pub const fn position(&self) -> usize {
self.i
}
#[inline]
#[must_use]
pub fn remaining(&self) -> usize {
self.b.lim.saturating_sub(self.i)
}
#[inline(always)]
pub fn skip(&mut self, n: usize) -> &mut Self {
self.i += n;
self
}
#[inline(always)]
pub fn bool<T: Into<bool>>(&mut self, v: T) -> &mut Self {
self.u8(v.into())
}
#[inline(always)]
pub fn u8<T: Into<u8>>(&mut self, v: T) -> &mut Self {
self.put([v.into()])
}
#[inline(always)]
pub fn u16<T: Into<u16>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn u24<T: Into<u32>>(&mut self, v: T) -> &mut Self {
let v = v.into().to_le_bytes();
assert_eq!(v[3], 0);
self.put(&v[..3])
}
#[inline(always)]
pub fn u32<T: Into<u32>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn u64<T: Into<u64>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn u128<T: Into<u128>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn i8<T: Into<i8>>(&mut self, v: T) -> &mut Self {
#[allow(clippy::cast_sign_loss)]
self.put([v.into() as u8])
}
#[inline(always)]
pub fn i16<T: Into<i16>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn i32<T: Into<i32>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn i64<T: Into<i64>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
pub fn i128<T: Into<i128>>(&mut self, v: T) -> &mut Self {
self.put(v.into().to_le_bytes())
}
#[inline(always)]
#[must_use]
pub const fn can_put(&self, n: usize) -> bool {
self.b.can_put_at(self.i, n)
}
#[inline]
pub fn put<T: AsRef<[u8]>>(&mut self, v: T) -> &mut Self {
let v = v.as_ref();
self.b.put_at(self.i, v);
self.i += v.len();
self
}
}
impl AsRef<[u8]> for Packer<'_> {
#[inline]
fn as_ref(&self) -> &[u8] {
unsafe { self.b.get_unchecked(self.b.len().min(self.i)..) }
}
}
impl AsMut<[u8]> for Packer<'_> {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
let i = self.b.len().min(self.i);
unsafe { self.b.get_unchecked_mut(i..) }
}
}
impl From<&mut Packer<'_>> for () {
#[inline(always)]
fn from(_: &mut Packer) -> Self {}
}
#[allow(single_use_lifetimes)]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[must_use]
#[repr(transparent)]
pub struct Unpacker<'a>(&'a [u8]);
impl<'a> Unpacker<'a> {
#[inline(always)]
pub const fn new(b: &'a [u8]) -> Self {
Self(b)
}
#[inline(always)]
#[must_use]
pub const fn into_inner(self) -> &'a [u8] {
self.0
}
#[inline(always)]
#[must_use]
pub const fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline(always)]
#[must_use]
pub fn is_ok(&self) -> bool {
!ptr::eq(self.0, Self::err())
}
#[inline]
pub fn take(&mut self) -> Self {
let empty = unsafe { self.0.get_unchecked(self.0.len()..) };
Self(mem::replace(&mut self.0, empty))
}
#[inline]
#[must_use]
pub fn map<T>(mut self, f: impl FnOnce(&mut Self) -> T) -> Option<T> {
let v = f(&mut self);
(self.is_ok() && self.0.is_empty()).then_some(v)
}
#[inline(always)]
#[must_use]
pub fn map_or<T>(self, default: T, f: impl FnOnce(&mut Self) -> T) -> T {
self.map(f).unwrap_or(default)
}
#[inline(always)]
pub fn map_or_else<T>(self, default: impl FnOnce() -> T, f: impl FnOnce(&mut Self) -> T) -> T {
self.map(f).unwrap_or_else(default)
}
#[inline]
pub const fn split_at(&self, i: usize) -> (Self, Self) {
let Some(rem) = self.0.len().checked_sub(i) else {
return (Self(Self::err()), Self(Self::err()));
};
let p = self.0.as_ptr();
unsafe {
(
Self(slice::from_raw_parts(p, i)),
Self(slice::from_raw_parts(p.add(i), rem)),
)
}
}
#[inline]
pub fn skip(&mut self, n: usize) -> Option<Self> {
let (a, b) = self.split_at(n);
self.0 = b.0;
a.is_ok().then_some(a)
}
#[inline(always)]
#[must_use]
pub fn bool(&mut self) -> bool {
self.u8() != 0
}
#[inline(always)]
#[must_use]
pub fn u8(&mut self) -> u8 {
unsafe { self.read() }
}
#[inline(always)]
#[must_use]
pub fn u16(&mut self) -> u16 {
u16::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn u32(&mut self) -> u32 {
u32::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn u64(&mut self) -> u64 {
u64::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn u128(&mut self) -> u128 {
u128::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn i8(&mut self) -> i8 {
unsafe { self.read() }
}
#[inline(always)]
#[must_use]
pub fn i16(&mut self) -> i16 {
i16::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn i32(&mut self) -> i32 {
i32::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn i64(&mut self) -> i64 {
i64::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn i128(&mut self) -> i128 {
i128::from_le(unsafe { self.read() })
}
#[inline(always)]
#[must_use]
pub fn bytes<const N: usize>(&mut self) -> [u8; N] {
if let Some(rem) = self.0.len().checked_sub(N) {
unsafe {
let p = self.0.as_ptr();
self.0 = slice::from_raw_parts(p.add(N), rem);
*p.cast()
}
} else {
self.0 = Self::err();
[0; N]
}
}
#[inline]
#[must_use]
pub unsafe fn read<T: Default>(&mut self) -> T {
if let Some(rem) = self.0.len().checked_sub(mem::size_of::<T>()) {
let p = self.0.as_ptr().cast::<T>();
self.0 = slice::from_raw_parts(p.add(1).cast(), rem);
p.read_unaligned()
} else {
self.0 = Self::err();
T::default()
}
}
#[inline(always)]
#[must_use]
const fn err() -> &'static [u8] {
unsafe { slice::from_raw_parts(ptr::NonNull::dangling().as_ptr(), 0) }
}
}
impl<'a> AsRef<[u8]> for Unpacker<'a> {
#[inline(always)]
#[must_use]
fn as_ref(&self) -> &'a [u8] {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn packer() {
let mut b = StructBuf::new(4);
assert_eq!(b.len(), 0);
assert_eq!(b.capacity(), 4);
assert_eq!(b.lim(), 4);
b.append().u8(1);
assert_eq!(b.len(), 1);
assert_eq!(b.as_ref(), &[1]);
b.append().u8(2).u16(0x0403_u16);
assert_eq!(b.len(), 4);
assert_eq!(b.as_ref(), &[1, 2, 3, 4]);
}
#[test]
#[should_panic]
fn packer_limit() {
let mut b = StructBuf::new(4);
b.append().u8(1).u16(2_u16);
b.append().u16(3_u16);
}
#[test]
fn packer_overwrite() {
let mut b = StructBuf::new(4);
b.append().put([1, 2, 3, 4]);
assert_eq!(b.as_ref(), &[1, 2, 3, 4]);
b.at(1).u16(0x0203_u16);
assert_eq!(b.as_ref(), &[1, 3, 2, 4]);
}
#[test]
fn packer_pad() {
let mut b = StructBuf::with_capacity(INLINE_CAP + 1);
unsafe { b.as_mut_ptr().write_bytes(0xFF, b.capacity()) };
b.at(b.capacity() - 1).u8(1);
assert!(&b[..INLINE_CAP].iter().all(|&v| v == 0));
assert_eq!(b[INLINE_CAP], 1);
b.clear();
b.put_at(4, []);
assert_eq!(b.as_ref(), &[0, 0, 0, 0]);
}
#[test]
fn unpacker() {
let mut p = Unpacker::new(&[1, 2, 3]);
assert_eq!(p.u8(), 1);
assert!(p.is_ok());
assert_eq!(p.u16(), 0x0302);
assert!(p.is_ok());
assert_eq!(p.u8(), 0);
assert!(!p.is_ok());
let mut p = Unpacker::new(&[1]);
assert_eq!(p.u16(), 0);
assert!(!p.is_ok());
assert_eq!(p.u32(), 0);
let mut p = Unpacker::new(&[1, 2, 3]);
assert_eq!(p.bytes::<2>(), [1, 2]);
assert_eq!(p.bytes::<3>(), [0, 0, 0]);
}
#[test]
fn unpacker_take() {
let mut p = Unpacker::new(&[1, 2, 3]);
assert_eq!(p.u8(), 1);
let mut v = p.take();
assert!(p.is_ok());
assert!(p.is_empty());
assert_eq!((v.u8(), v.u8()), (2, 3));
assert!(v.is_ok());
assert_eq!(p.u64(), 0);
assert!(!p.is_ok());
let v = p.take();
assert!(!v.is_ok());
}
#[test]
fn unpacker_skip() {
let mut p = Unpacker::new(&[1, 2, 3]);
let mut v = p.skip(2).unwrap();
assert_eq!((v.u8(), v.u8()), (1, 2));
assert_eq!(p.u8(), 3);
assert!(p.skip(0).unwrap().is_ok());
assert!(p.is_ok());
assert!(p.skip(1).is_none());
assert!(!p.is_ok());
}
}