use core::ops::Range;
#[derive(Copy, Clone)]
pub struct Bytes<'a>(pub &'a [u8]);
impl<'a> Bytes<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self(data)
}
pub fn with_offset(data: &'a [u8], offset: usize) -> Option<Self> {
Some(Self(data.get(offset..)?))
}
pub fn with_range(data: &'a [u8], range: Range<usize>) -> Option<Self> {
Some(Self(data.get(range)?))
}
pub fn data(&self) -> &'a [u8] {
self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn check_range(&self, offset: usize, len: usize) -> bool {
let end = self.0.len();
(offset < end) & (end - offset >= len)
}
pub fn ensure_range(&self, offset: usize, len: usize) -> Option<()> {
if self.check_range(offset, len) {
Some(())
} else {
None
}
}
#[inline(always)]
pub fn read<T: FromBeData>(&self, offset: usize) -> Option<T> {
T::from_be_data(self.0, offset)
}
#[inline(always)]
pub fn read_u8(&self, offset: usize) -> Option<u8> {
u8::from_be_data(self.0, offset)
}
#[inline(always)]
pub fn read_u16(&self, offset: usize) -> Option<u16> {
u16::from_be_data(self.0, offset)
}
#[inline(always)]
pub fn read_u24(&self, offset: usize) -> Option<u32> {
U24::from_be_data(self.0, offset).map(|x| x.0)
}
#[inline(always)]
pub fn read_u32(&self, offset: usize) -> Option<u32> {
u32::from_be_data(self.0, offset)
}
#[inline(always)]
pub fn read_i8(&self, offset: usize) -> Option<i8> {
i8::from_be_data(self.0, offset)
}
#[inline(always)]
pub fn read_i16(&self, offset: usize) -> Option<i16> {
i16::from_be_data(self.0, offset)
}
pub fn read_or_default<T: FromBeData + Default>(&self, offset: usize) -> T {
T::from_be_data(self.0, offset).unwrap_or_default()
}
#[inline(always)]
pub unsafe fn read_unchecked<T: FromBeData>(&self, offset: usize) -> T {
T::from_be_data_unchecked(self.0, offset)
}
pub fn read_array<T: FromBeData>(&self, offset: usize, len: usize) -> Option<Array<'a, T>> {
let len = len * T::SIZE;
if !self.check_range(offset, len) {
return None;
}
Some(Array::new(&self.0[offset..offset + len]))
}
pub fn read_bytes(&self, offset: usize, len: usize) -> Option<&'a [u8]> {
if !self.check_range(offset, len) {
return None;
}
Some(&self.0[offset..offset + len])
}
pub fn stream_at(&self, offset: usize) -> Option<Stream<'a>> {
Stream::with_offset(self.0, offset)
}
}
impl<'a> core::ops::Deref for Bytes<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.0
}
}
#[derive(Copy, Clone)]
pub struct Stream<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> Stream<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, offset: 0 }
}
pub fn with_offset(data: &'a [u8], offset: usize) -> Option<Self> {
let data = data.get(offset..)?;
Some(Self { data, offset: 0 })
}
pub fn with_range(data: &'a [u8], range: Range<usize>) -> Option<Self> {
let data = data.get(range)?;
Some(Self { data, offset: 0 })
}
pub fn data(&self) -> &'a [u8] {
self.data
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn offset(&self) -> usize {
self.offset
}
pub fn remaining(&self) -> usize {
self.data.len() - self.offset
}
pub fn set_offset(&mut self, offset: usize) -> Option<()> {
if offset > self.data.len() {
return None;
}
self.offset = offset;
Some(())
}
pub fn check_range(&self, len: usize) -> bool {
self.data.len() - self.offset >= len
}
pub fn ensure_range(&self, len: usize) -> Option<()> {
if self.check_range(len) {
Some(())
} else {
None
}
}
pub fn skip(&mut self, bytes: usize) -> Option<()> {
self.set_offset(self.offset.checked_add(bytes)?)
}
pub fn read<T: FromBeData>(&mut self) -> Option<T> {
if self.data.len() - self.offset < T::SIZE {
None
} else {
let v = unsafe { T::from_be_data_unchecked(self.data, self.offset) };
self.offset += T::SIZE;
Some(v)
}
}
#[inline(always)]
pub fn read_u8(&mut self) -> Option<u8> {
self.read::<u8>()
}
#[inline(always)]
pub fn read_u16(&mut self) -> Option<u16> {
self.read::<u16>()
}
#[inline(always)]
pub fn read_u32(&mut self) -> Option<u32> {
self.read::<u32>()
}
#[inline(always)]
pub fn read_i8(&mut self) -> Option<i8> {
self.read::<i8>()
}
#[inline(always)]
pub fn read_i16(&mut self) -> Option<i16> {
self.read::<i16>()
}
pub fn read_array<T: FromBeData>(&mut self, len: usize) -> Option<Array<'a, T>> {
let len = len * T::SIZE;
if !self.check_range(len) {
return None;
}
let arr = Array::new(&self.data[self.offset..self.offset + len]);
self.offset += len;
Some(arr)
}
pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
if !self.check_range(len) {
return None;
}
let bytes = &self.data[self.offset..self.offset + len];
self.offset += len;
Some(bytes)
}
}
#[derive(Copy, Clone)]
pub struct Array<'a, T: FromBeData> {
data: &'a [u8],
len: usize,
_p: core::marker::PhantomData<T>,
}
impl<T> core::fmt::Debug for Array<'_, T>
where
T: core::fmt::Debug + FromBeData,
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "[")?;
for (i, value) in self.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{:?}", value)?;
}
write!(f, "]")
}
}
impl<'a, T: FromBeData> Array<'a, T> {
pub(crate) fn new(data: &'a [u8]) -> Self {
Self {
data,
len: data.len() / T::SIZE,
_p: core::marker::PhantomData {},
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn get(&self, index: usize) -> Option<T> {
if index >= self.len {
None
} else {
unsafe { Some(T::from_be_data_unchecked(self.data, index * T::SIZE)) }
}
}
pub fn get_or(&self, index: usize, or: T) -> T {
if index >= self.len {
or
} else {
unsafe { T::from_be_data_unchecked(self.data, index * T::SIZE) }
}
}
pub unsafe fn get_unchecked(&self, index: usize) -> T {
T::from_be_data_unchecked(self.data, index * T::SIZE)
}
pub fn binary_search_by<F>(&self, mut f: F) -> Option<(usize, T)>
where
F: FnMut(&T) -> core::cmp::Ordering,
{
use core::cmp::Ordering::*;
let mut size = self.len;
if size == 0 {
return None;
}
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
let element = unsafe { self.get_unchecked(mid) };
base = match f(&element) {
Greater => base,
Less => mid,
Equal => return Some((mid, element)),
};
size -= half;
}
None
}
pub fn iter(&self) -> ArrayIter<'a, T> {
ArrayIter {
inner: *self,
cur: 0,
}
}
}
#[derive(Clone)]
#[doc(hidden)]
pub struct ArrayIter<'a, T: FromBeData> {
inner: Array<'a, T>,
cur: usize,
}
impl<'a, T: FromBeData + 'a> Iterator for ArrayIter<'a, T> {
type Item = T;
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.inner.len - self.cur;
(remaining, Some(remaining))
}
fn next(&mut self) -> Option<T> {
if self.cur >= self.inner.len {
return None;
}
self.cur += 1;
unsafe { Some(self.inner.get_unchecked(self.cur - 1)) }
}
}
impl<'a, T: FromBeData + 'a> IntoIterator for Array<'a, T> {
type IntoIter = ArrayIter<'a, T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
ArrayIter {
inner: self,
cur: 0,
}
}
}
pub trait FromBeData: Sized + Copy + Clone {
const SIZE: usize = core::mem::size_of::<Self>();
#[inline(always)]
fn from_be_data(buf: &[u8], offset: usize) -> Option<Self> {
let len = buf.len();
if (offset < len) && ((len - offset) >= Self::SIZE) {
unsafe { Some(Self::from_be_data_unchecked(buf, offset)) }
} else {
None
}
}
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self;
}
pub(crate) const USE_UNALIGNED_READS_LE: bool =
cfg!(any(target_arch = "x86", target_arch = "x86_64")) && cfg!(not(debug_assertions));
impl FromBeData for u8 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
*buf.get_unchecked(offset)
}
}
impl FromBeData for i8 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
*buf.get_unchecked(offset) as i8
}
}
impl FromBeData for u16 {
#[inline(always)]
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
if USE_UNALIGNED_READS_LE {
(buf.as_ptr().add(offset) as *const u16)
.read_unaligned()
.swap_bytes()
} else {
(*buf.get_unchecked(offset) as u16) << 8 | *buf.get_unchecked(offset + 1) as u16
}
}
}
impl FromBeData for i16 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
u16::from_be_data_unchecked(buf, offset) as i16
}
}
impl FromBeData for u32 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
if USE_UNALIGNED_READS_LE {
(buf.as_ptr().add(offset) as *const u32)
.read_unaligned()
.swap_bytes()
} else {
(*buf.get_unchecked(offset) as u32) << 24
| (*buf.get_unchecked(offset + 1) as u32) << 16
| (*buf.get_unchecked(offset + 2) as u32) << 8
| *buf.get_unchecked(offset + 3) as u32
}
}
}
impl FromBeData for i32 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
u32::from_be_data_unchecked(buf, offset) as i32
}
}
impl FromBeData for u64 {
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
if USE_UNALIGNED_READS_LE {
(buf.as_ptr().add(offset) as *const u64)
.read_unaligned()
.swap_bytes()
} else {
(*buf.get_unchecked(offset) as u64) << 56
| (*buf.get_unchecked(offset + 1) as u64) << 48
| (*buf.get_unchecked(offset + 2) as u64) << 40
| (*buf.get_unchecked(offset + 3) as u64) << 32
| (*buf.get_unchecked(offset + 4) as u64) << 24
| (*buf.get_unchecked(offset + 5) as u64) << 16
| (*buf.get_unchecked(offset + 6) as u64) << 8
| *buf.get_unchecked(offset + 7) as u64
}
}
}
#[derive(Copy, Clone)]
#[doc(hidden)]
pub struct U24(pub u32);
impl FromBeData for U24 {
const SIZE: usize = 3;
unsafe fn from_be_data_unchecked(buf: &[u8], offset: usize) -> Self {
Self(
(*buf.get_unchecked(offset) as u32) << 16
| (*buf.get_unchecked(offset + 1) as u32) << 8
| *buf.get_unchecked(offset + 2) as u32,
)
}
}
impl FromBeData for () {
unsafe fn from_be_data_unchecked(_buf: &[u8], _offset: usize) -> Self {}
}