use crate::core::layout::LayoutParseError;
pub trait View {
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError>;
#[inline]
fn from_slice(buf: &[u8]) -> Result<(&Self, &[u8]), ViewConversionError> {
let size = Self::has_required_size(buf)?;
debug_assert!(buf.len() >= size);
let (view_buf, rest) = unsafe { buf.split_at_unchecked(size) };
let view = unsafe { Self::from_slice_unchecked(view_buf) };
Ok((view, rest))
}
#[inline]
fn from_mut_slice(buf: &mut [u8]) -> Result<(&mut Self, &mut [u8]), ViewConversionError> {
let size = Self::has_required_size(buf)?;
debug_assert!(buf.len() >= size);
let (view_buf, rest) = unsafe { buf.split_at_mut_unchecked(size) };
let view = unsafe { Self::from_mut_slice_unchecked(view_buf) };
Ok((view, rest))
}
#[inline]
fn from_boxed(buf: Box<[u8]>) -> Result<Box<Self>, ViewConversionError> {
let size = Self::has_required_size(&buf)?;
if buf.len() != size {
return Err(ViewConversionError::Other(
"Boxed buffer size does not match view size",
));
}
Ok(unsafe { Self::from_boxed_unchecked(buf) })
}
fn as_bytes(&self) -> &[u8];
unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]>;
#[inline]
fn to_owned(&self) -> Box<Self> {
unsafe { Self::from_boxed_unchecked(self.as_bytes().to_vec().into_boxed_slice()) }
}
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self;
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self;
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self>;
}
#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq, Eq, Hash)]
pub enum ViewConversionError {
#[error("Buffer too small at {at}: required {required}, got {actual}")]
BufferTooSmall {
at: &'static str,
required: usize,
actual: usize,
},
#[error("Could not convert view: {0}")]
Other(&'static str),
}
impl From<LayoutParseError> for ViewConversionError {
fn from(value: LayoutParseError) -> Self {
match value {
LayoutParseError::BufferTooSmall {
at,
required,
actual,
} => {
ViewConversionError::BufferTooSmall {
at,
required,
actual,
}
}
LayoutParseError::InvalidHeaderLength { .. } => {
ViewConversionError::Other("InvalidHeaderLength")
}
LayoutParseError::UnsupportedVersion => {
ViewConversionError::Other("UnsupportedVersion")
}
}
}
}
pub(crate) mod macros {
macro_rules! gen_field_read_and_write {
($get_name:ident, $set_name:ident, $bit_range:expr, $repr:ty) => {
gen_field_read!($get_name, $bit_range, $repr);
gen_field_write!($set_name, $bit_range, $repr);
};
}
pub(crate) use gen_field_read_and_write;
macro_rules! gen_field_read {
($name:ident, $bit_range:expr, $repr:ty) => {
#[inline]
#[allow(unused)]
pub fn $name(&self) -> $repr {
use $crate::core::read::unchecked_bit_range_be_read;
unsafe { unchecked_bit_range_be_read::<$repr>(&self.0, $bit_range) }
}
};
}
pub(crate) use gen_field_read;
macro_rules! gen_field_write {
($name:ident, $bit_range:expr, $repr:ty) => {
#[inline]
#[allow(unused)]
pub fn $name(&mut self, value: $repr) {
use $crate::core::write::unchecked_bit_range_be_write;
unsafe { unchecked_bit_range_be_write::<$repr>(&mut self.0, $bit_range, value) }
}
};
}
pub(crate) use gen_field_write;
macro_rules! gen_unsafe_field_write {
($name:ident, $bit_range:expr, $repr:ty) => {
#[inline]
#[allow(unused)]
pub unsafe fn $name(&mut self, value: $repr) {
use $crate::core::write::unchecked_bit_range_be_write;
unsafe { unchecked_bit_range_be_write::<$repr>(&mut self.0, $bit_range, value) }
}
};
}
pub(crate) use gen_unsafe_field_write;
macro_rules! gen_view_impl {
($name:ident, $layout:ident) => {
impl View for $name {
fn has_required_size(buf: &[u8]) -> Result<usize, ViewConversionError> {
use crate::core::layout::Layout;
let layout = $layout::try_from(buf)?;
Ok(layout.size_bytes())
}
fn as_bytes(&self) -> &[u8] {
&self.0
}
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}
fn as_bytes_boxed(self: Box<Self>) -> Box<[u8]> {
unsafe { std::mem::transmute(self) }
}
unsafe fn from_slice_unchecked(buf: &[u8]) -> &Self {
unsafe { std::mem::transmute(buf) }
}
unsafe fn from_mut_slice_unchecked(buf: &mut [u8]) -> &mut Self {
unsafe { std::mem::transmute(buf) }
}
unsafe fn from_boxed_unchecked(buf: Box<[u8]>) -> Box<Self> {
unsafe { std::mem::transmute(buf) }
}
}
};
}
pub(crate) use gen_view_impl;
}