use core::{
alloc::Layout,
marker::PhantomData,
mem,
ops::{Deref, DerefMut},
ptr::{self, NonNull},
slice,
};
#[cfg(feature = "std")]
use std::alloc;
#[cfg(not(feature = "std"))]
extern crate alloc as no_std_alloc;
#[cfg(not(feature = "std"))]
use no_std_alloc::alloc;
use try_reserve::error::TryReserveError;
pub struct Sector<State, T> {
pub(super) buf: RawSec<T>,
pub(super) len: usize,
pub(super) _state: PhantomData<State>,
}
impl<State, T> Sector<State, T> {
#[allow(clippy::new_without_default)]
pub fn new() -> Sector<State, T> {
Sector {
buf: RawSec::new(),
len: 0,
_state: PhantomData,
}
}
pub fn with_capacity(capacity: usize) -> Sector<State, T> {
Sector {
buf: RawSec::with_capacity(capacity),
len: 0,
_state: PhantomData,
}
}
pub fn try_with_capacity(capacity: usize) -> Result<Sector<State, T>, TryReserveError> {
Ok(Sector {
buf: RawSec::try_with_capacity(capacity)?,
len: 0,
_state: PhantomData,
})
}
#[allow(dead_code)]
pub unsafe fn as_ptr(&self) -> NonNull<T> {
self.buf.ptr
}
#[allow(dead_code)]
pub(crate) unsafe fn as_mut_ptr(&mut self) -> NonNull<T> {
self.buf.ptr
}
#[allow(dead_code)]
pub(crate) unsafe fn set_ptr(&mut self, new_ptr: NonNull<T>) {
self.buf.ptr = new_ptr;
}
#[allow(dead_code)]
pub fn capacity(&self) -> usize {
self.buf.cap
}
#[allow(dead_code)]
pub(crate) unsafe fn set_capacity(&mut self, new_cap: usize) {
self.buf.cap = new_cap;
}
#[allow(dead_code)]
pub fn len(&self) -> usize {
self.len
}
#[allow(dead_code)]
pub unsafe fn set_len(&mut self, new_len: usize) {
self.len = new_len;
}
}
impl<State, T> Drop for Sector<State, T> {
fn drop(&mut self) {
if self.len > 0 && mem::size_of::<T>() != 0 {
for i in 0..self.len {
unsafe {
let ptr = self.buf.ptr.as_ptr().add(i);
ptr::drop_in_place(ptr);
}
}
}
}
}
impl<State, T> Deref for Sector<State, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { slice::from_raw_parts(self.buf.ptr.as_ptr(), self.len) }
}
}
impl<State, T> DerefMut for Sector<State, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { slice::from_raw_parts_mut(self.buf.ptr.as_ptr(), self.len) }
}
}
pub(super) struct RawSec<T> {
pub(super) ptr: NonNull<T>,
pub(super) cap: usize,
}
struct RawIter<T> {
start: *const T,
end: *const T,
}
impl<T> RawIter<T> {
unsafe fn new(slice: &[T]) -> Self {
RawIter {
start: slice.as_ptr(),
end: if size_of::<T>() == 0 {
((slice.as_ptr() as usize) + slice.len()) as *const _
} else if slice.is_empty() {
slice.as_ptr()
} else {
slice.as_ptr().add(slice.len())
},
}
}
}
impl<T> RawSec<T> {
fn new() -> Self {
let (ptr, cap) = Self::create_ptr(None).unwrap();
RawSec { ptr, cap }
}
fn with_capacity(capacity: usize) -> Self {
let (ptr, cap) = Self::create_ptr(Some(capacity))
.unwrap_or_else(|_| panic!("The given capacity {capacity} overflows the layout"));
RawSec { ptr, cap }
}
#[allow(dead_code)]
fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
let (ptr, cap) = Self::create_ptr(Some(capacity))?;
Ok(RawSec { ptr, cap })
}
fn create_ptr(initial_capacity: Option<usize>) -> Result<(NonNull<T>, usize), TryReserveError> {
let capacity = initial_capacity.unwrap_or_default();
if size_of::<T>() == 0 {
return Ok((NonNull::dangling(), !0));
}
if capacity == 0 {
return Ok((NonNull::dangling(), 0));
}
let layout = Layout::array::<T>(capacity)?;
let ptr = unsafe { NonNull::new(alloc::alloc(layout) as *mut T) };
match ptr {
Some(ptr) => Ok((ptr, capacity)),
None => alloc::handle_alloc_error(layout),
}
}
}
impl<T> Drop for RawSec<T> {
fn drop(&mut self) {
if self.cap != 0 && size_of::<T>() != 0 {
let layout = Layout::array::<T>(self.cap).unwrap();
unsafe { alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout) }
}
}
}
pub struct IntoIter<T> {
_buf: RawSec<T>,
iter: RawIter<T>,
}
impl<T> Iterator for RawIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
None
} else {
unsafe {
let result = ptr::read(self.start);
self.start = if size_of::<T>() == 0 {
(self.start as usize + 1) as *const _
} else {
self.start.offset(1)
};
Some(result)
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = (self.end as usize - self.start as usize) / size_of::<T>();
(size, Some(size))
}
}
impl<T> DoubleEndedIterator for RawIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.start == self.end {
None
} else {
unsafe {
self.end = if size_of::<T>() == 0 {
(self.end as usize - 1) as *const _
} else {
self.end.offset(-1)
};
Some(ptr::read(self.end))
}
}
}
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
for _ in &mut *self {}
}
}
impl<State: crate::components::DefaultIter, T> IntoIterator for Sector<State, T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
unsafe {
let iter = RawIter::new(&self);
let buf = ptr::read(&self.buf);
mem::forget(self);
IntoIter { iter, _buf: buf }
}
}
}
impl<State: crate::components::DefaultDrain, T> Sector<State, T> {
pub fn drain(&mut self) -> Drain<'_, T> {
let iter = unsafe { RawIter::new(self) };
self.len = 0;
Drain {
iter,
sec: PhantomData,
}
}
}
pub struct Drain<'a, T: 'a> {
sec: PhantomData<&'a mut Sector<(), T>>,
iter: RawIter<T>,
}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
for _ in &mut *self {}
}
}