use core::{
alloc::Layout,
borrow::{Borrow, BorrowMut},
fmt,
marker::PhantomData,
mem::MaybeUninit,
ops,
ptr::NonNull,
slice::{self, from_raw_parts_mut},
};
use rancor::Fallible;
use crate::ser::Allocator;
pub struct SerVec<T> {
ptr: NonNull<T>,
cap: usize,
len: usize,
}
unsafe impl<T: Send> Send for SerVec<T> {}
unsafe impl<T: Sync> Sync for SerVec<T> {}
impl<T> SerVec<T> {
pub fn with_capacity<S, R>(
serializer: &mut S,
cap: usize,
f: impl FnOnce(&mut Self, &mut S) -> R,
) -> Result<R, S::Error>
where
S: Fallible + Allocator + ?Sized,
{
let layout = Layout::array::<T>(cap).unwrap();
let mut vec = Self {
ptr: if layout.size() != 0 {
unsafe { serializer.push_alloc(layout)?.cast() }
} else {
NonNull::dangling()
},
cap,
len: 0,
};
let result = f(&mut vec, serializer);
vec.clear();
if layout.size() != 0 {
unsafe {
serializer.pop_alloc(vec.ptr.cast(), layout)?;
}
}
Ok(result)
}
pub fn clear(&mut self) {
for i in 0..self.len {
unsafe {
core::ptr::drop_in_place(self.ptr.as_ptr().add(i));
}
}
self.len = 0;
}
pub fn as_mut_ptr(&mut self) -> *mut T {
self.ptr.as_ptr()
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
pub fn as_ptr(&self) -> *const T {
self.ptr.as_ptr()
}
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}
pub fn capacity(&self) -> usize {
self.cap
}
pub fn reserve(&mut self, additional: usize) {
if self.cap - self.len < additional {
Self::out_of_space();
}
}
#[cold]
fn out_of_space() -> ! {
panic!("reserve requested more capacity than the SerVec has available");
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn len(&self) -> usize {
self.len
}
pub fn extend_from_slice(&mut self, other: &[T])
where
T: Copy,
{
if !other.is_empty() {
self.reserve(other.len());
unsafe {
core::ptr::copy_nonoverlapping(
other.as_ptr(),
self.as_mut_ptr().add(self.len()),
other.len(),
);
}
self.len += other.len();
}
}
pub fn pop(&mut self) -> Option<T> {
if self.len == 0 {
None
} else {
unsafe {
self.len -= 1;
Some(self.as_ptr().add(self.len()).read())
}
}
}
pub unsafe fn push_unchecked(&mut self, value: T) {
unsafe {
self.as_mut_ptr().add(self.len).write(value);
}
self.len += 1;
}
pub fn push(&mut self, value: T) {
if self.len == self.cap {
Self::out_of_space()
} else {
unsafe {
self.push_unchecked(value);
}
}
}
pub fn reserve_exact(&mut self, additional: usize) {
self.reserve(additional);
}
pub unsafe fn set_len(&mut self, new_len: usize) {
debug_assert!(new_len <= self.capacity());
self.len = new_len;
}
pub fn drain(&mut self) -> Drain<'_, T> {
let remaining = self.len();
unsafe {
self.set_len(0);
}
Drain {
current: self.ptr,
remaining,
_phantom: PhantomData,
}
}
}
impl<T> SerVec<MaybeUninit<T>> {
pub fn assume_init(self) -> SerVec<T> {
SerVec {
ptr: self.ptr.cast(),
cap: self.cap,
len: self.len,
}
}
}
impl<T> AsMut<[T]> for SerVec<T> {
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> AsRef<[T]> for SerVec<T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Borrow<[T]> for SerVec<T> {
fn borrow(&self) -> &[T] {
self.as_slice()
}
}
impl<T> BorrowMut<[T]> for SerVec<T> {
fn borrow_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T: fmt::Debug> fmt::Debug for SerVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_slice().fmt(f)
}
}
impl<T> ops::Deref for SerVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T> ops::DerefMut for SerVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T, I: slice::SliceIndex<[T]>> ops::Index<I> for SerVec<T> {
type Output = <I as slice::SliceIndex<[T]>>::Output;
fn index(&self, index: I) -> &Self::Output {
&self.as_slice()[index]
}
}
impl<T, I: slice::SliceIndex<[T]>> ops::IndexMut<I> for SerVec<T> {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.as_mut_slice()[index]
}
}
pub struct Drain<'a, T: 'a> {
current: NonNull<T>,
remaining: usize,
_phantom: PhantomData<&'a mut SerVec<T>>,
}
impl<T: fmt::Debug> fmt::Debug for Drain<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.as_slice()).finish()
}
}
impl<T> Drain<'_, T> {
pub fn as_slice(&self) -> &[T] {
unsafe { from_raw_parts_mut(self.current.as_ptr(), self.remaining) }
}
}
impl<T> AsRef<[T]> for Drain<'_, T> {
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> Iterator for Drain<'_, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.remaining > 0 {
self.remaining -= 1;
let result = unsafe { self.current.as_ptr().read() };
self.current =
unsafe { NonNull::new_unchecked(self.current.as_ptr().add(1)) };
Some(result)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T> DoubleEndedIterator for Drain<'_, T> {
fn next_back(&mut self) -> Option<T> {
if self.remaining > 0 {
self.remaining -= 1;
unsafe { Some(self.current.as_ptr().add(self.remaining).read()) }
} else {
None
}
}
}
impl<T> Drop for Drain<'_, T> {
fn drop(&mut self) {
for i in 0..self.remaining {
unsafe {
self.current.as_ptr().add(i).drop_in_place();
}
}
}
}
impl<T> ExactSizeIterator for Drain<'_, T> {}
impl<T> core::iter::FusedIterator for Drain<'_, T> {}