use core::cmp::Ordering;
use core::fmt;
use core::hash::Hash;
use core::marker::PhantomData;
use core::mem::size_of;
use crate::pointer::{DefaultSize, Ref, Size};
use crate::ZeroCopy;
#[derive(ZeroCopy)]
#[repr(C)]
#[zero_copy(crate)]
pub struct Slice<T, O: Size = DefaultSize> {
offset: O,
len: O,
#[zero_copy(ignore)]
_marker: PhantomData<T>,
}
impl<T, O: Size> Slice<T, O>
where
T: ZeroCopy,
{
pub fn new(offset: usize, len: usize) -> Self {
let Some(offset) = O::from_usize(offset) else {
panic!(
"Slice offset {offset} not in the legal range of 0-{}",
O::MAX
);
};
let Some(len) = O::from_usize(len) else {
panic!("Slice length {len} not in the legal range of 0-{}", O::MAX);
};
Self {
offset,
len,
_marker: PhantomData,
}
}
pub(crate) fn new_with_offset(offset: O, len: usize) -> Self {
let Some(len) = O::from_usize(len) else {
panic!("Slice length {len} not in the legal range of 0-{}", O::MAX);
};
Self {
offset,
len,
_marker: PhantomData,
}
}
#[inline]
pub fn offset(&self) -> usize {
self.offset.as_usize()
}
#[inline]
pub fn len(&self) -> usize {
self.len.as_usize()
}
pub fn is_empty(&self) -> bool {
self.len.is_zero()
}
pub fn get(&self, index: usize) -> Option<Ref<T, O>> {
if index >= self.len() {
return None;
}
let ptr = self
.offset()
.wrapping_add(size_of::<T>().wrapping_mul(index));
Some(Ref::new(ptr))
}
}
impl<T, O: Size> fmt::Debug for Slice<T, O>
where
O: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Slice<{}> {{ offset: {:?}, len: {:?} }}",
core::any::type_name::<T>(),
self.offset,
self.len
)
}
}
impl<T, O: Size> Clone for Slice<T, O>
where
T: ZeroCopy,
{
fn clone(&self) -> Self {
*self
}
}
impl<T, O: Size> Copy for Slice<T, O> where T: ZeroCopy {}
impl<T, O: Size> PartialEq for Slice<T, O>
where
O: PartialEq,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset && self.len == other.len
}
}
impl<T, O: Size> Eq for Slice<T, O> where O: Eq {}
impl<T, O: Size> PartialOrd for Slice<T, O>
where
O: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match self.offset.partial_cmp(&other.offset) {
Some(Ordering::Equal) => {}
ord => return ord,
}
self.len.partial_cmp(&other.len)
}
}
impl<T, O: Size> Ord for Slice<T, O>
where
O: Ord,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match self.offset.cmp(&other.offset) {
Ordering::Equal => {}
ord => return ord,
}
self.len.cmp(&other.len)
}
}
impl<T, O: Size> Hash for Slice<T, O>
where
O: Hash,
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.offset.hash(state);
self.len.hash(state);
}
}