mod macros;
mod raw_vec;
mod raw_vec_inner;
mod soable;
use core::marker::PhantomData;
use std::ptr::NonNull;
use raw_vec::RawSoAVec;
use raw_vec_inner::AllocError;
pub use soable::{SoATuple, SoAble};
#[cfg(feature = "derive")]
pub use soavec_derive::*;
#[repr(C)]
pub struct SoAVec<T: SoAble> {
buf: RawSoAVec<T>,
}
#[derive(Clone, Debug)]
pub struct IndexOutOfBoundsError;
#[derive(Clone, Debug)]
pub enum InsertError {
IndexOutOfBounds(IndexOutOfBoundsError),
AllocError(AllocError),
}
impl From<IndexOutOfBoundsError> for InsertError {
fn from(e: IndexOutOfBoundsError) -> Self {
InsertError::IndexOutOfBounds(e)
}
}
impl From<AllocError> for InsertError {
fn from(e: AllocError) -> Self {
InsertError::AllocError(e)
}
}
impl<T: SoAble> SoAVec<T> {
pub fn new() -> Self {
SoAVec {
buf: unsafe { RawSoAVec::with_capacity(0).unwrap_unchecked() },
}
}
pub fn with_capacity(cap: u32) -> Result<Self, AllocError> {
Ok(SoAVec {
buf: RawSoAVec::with_capacity(cap)?,
})
}
#[inline]
pub fn len(&self) -> u32 {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
#[inline]
pub fn capacity(&self) -> u32 {
self.buf.capacity()
}
pub fn reserve(&mut self, additional: u32) -> Result<(), AllocError> {
self.buf.reserve(additional)
}
pub fn push(&mut self, value: T) -> Result<(), AllocError> {
let len = self.len();
if len == self.capacity() {
self.buf.reserve(1)?;
}
unsafe {
T::TupleRepr::write(
self.buf.as_mut_ptr(),
T::into_tuple(value),
len,
self.capacity(),
)
};
unsafe { self.buf.set_len(self.len().unchecked_add(1)) };
Ok(())
}
pub fn append(&mut self, other: &mut Self) -> Result<(), AllocError> {
let other_len = other.len();
if other_len == 0 {
return Ok(());
}
self.reserve(other_len)?;
let self_len = self.len();
let self_cap = self.capacity();
let other_cap = other.capacity();
unsafe {
T::TupleRepr::copy(
T::TupleRepr::get_pointers(other.buf.as_ptr(), 0, other_cap),
T::TupleRepr::get_pointers(self.buf.as_mut_ptr(), self_len, self_cap),
other_len,
);
self.buf.set_len(self_len + other_len);
other.buf.set_len(0);
}
Ok(())
}
pub fn extend_from_slice(&mut self, slice: &[T]) -> Result<(), AllocError>
where
T: Clone,
{
let slice_len = slice.len() as u32;
if slice_len == 0 {
return Ok(());
}
self.reserve(slice_len)?;
let mut self_len = self.len();
let self_cap = self.capacity();
for item in slice.iter() {
unsafe {
T::TupleRepr::write(
self.buf.as_mut_ptr(),
T::into_tuple(item.clone()),
self_len,
self_cap,
);
}
self_len += 1;
}
unsafe {
self.buf.set_len(self_len);
}
Ok(())
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
let len = self.len();
if len == 0 {
None
} else {
unsafe {
self.buf.set_len(len - 1);
core::hint::assert_unchecked(self.len() < self.capacity());
Some(T::from_tuple(T::TupleRepr::read(
self.buf.as_ptr(),
self.len(),
self.capacity(),
)))
}
}
}
#[inline]
#[must_use]
pub fn get(&self, index: u32) -> Option<T::Ref<'_>> {
if self.len() <= index {
return None;
}
let ptrs = unsafe { T::TupleRepr::get_pointers(self.buf.as_ptr(), index, self.capacity()) };
Some(T::as_ref(PhantomData, ptrs))
}
#[inline]
#[must_use]
pub fn get_mut(&mut self, index: u32) -> Option<T::Mut<'_>> {
if self.len() <= index {
return None;
}
let ptrs =
unsafe { T::TupleRepr::get_pointers(self.buf.as_mut_ptr(), index, self.capacity()) };
Some(T::as_mut(PhantomData, ptrs))
}
pub fn as_slice(&self) -> T::Slice<'_> {
let ptrs = unsafe { T::TupleRepr::get_pointers(self.buf.as_ptr(), 0, self.capacity()) };
let len = self.len();
T::as_slice(PhantomData, ptrs, len)
}
pub fn as_mut_slice(&mut self) -> T::SliceMut<'_> {
let ptrs = unsafe { T::TupleRepr::get_pointers(self.buf.as_ptr(), 0, self.capacity()) };
let len = self.len();
T::as_mut_slice(PhantomData, ptrs, len)
}
pub fn retain_mut<F>(&mut self, mut f: F)
where
F: FnMut(T::Mut<'_>) -> bool,
{
let original_len = self.len();
if original_len == 0 {
return;
}
unsafe { self.buf.set_len(0) };
struct BackshiftOnDrop<'a, T: SoAble> {
v: &'a mut SoAVec<T>,
processed_len: u32,
deleted_cnt: u32,
original_len: u32,
}
impl<T: SoAble> Drop for BackshiftOnDrop<'_, T> {
fn drop(&mut self) {
if self.deleted_cnt > 0 {
let cap = self.v.buf.capacity();
unsafe {
T::TupleRepr::copy(
T::TupleRepr::get_pointers(
self.v.buf.as_ptr(),
self.processed_len,
cap,
),
T::TupleRepr::get_pointers(
self.v.buf.as_mut_ptr(),
self.processed_len - self.deleted_cnt,
cap,
),
self.original_len - self.processed_len,
);
}
}
unsafe {
self.v.buf.set_len(self.original_len - self.deleted_cnt);
}
}
}
let mut g = BackshiftOnDrop {
v: self,
processed_len: 0,
deleted_cnt: 0,
original_len,
};
fn process_loop<F, T: SoAble, const DELETED: bool>(
original_len: u32,
f: &mut F,
g: &mut BackshiftOnDrop<'_, T>,
) where
F: FnMut(T::Mut<'_>) -> bool,
{
while g.processed_len != original_len {
let cur_ptrs = unsafe {
T::TupleRepr::get_pointers(
g.v.buf.as_mut_ptr(),
g.processed_len,
g.v.capacity(),
)
};
let cur = T::as_mut(PhantomData, cur_ptrs);
if !f(cur) {
let cur_len = g.processed_len;
g.processed_len += 1;
g.deleted_cnt += 1;
if T::MUST_DROP_AS_SELF {
let ptr = g.v.buf.as_mut_ptr();
let cap = g.v.buf.capacity();
let _ = T::from_tuple(unsafe { T::TupleRepr::read(ptr, cur_len, cap) });
} else if const { core::mem::needs_drop::<T::TupleRepr>() } {
unsafe { T::TupleRepr::drop_in_place(cur_ptrs, 1) };
}
if DELETED {
continue;
} else {
break;
}
}
if DELETED {
unsafe {
let hole_slot = T::TupleRepr::get_pointers(
g.v.buf.as_mut_ptr(),
g.processed_len - g.deleted_cnt,
g.v.buf.capacity(),
);
T::TupleRepr::copy(cur_ptrs, hole_slot, 1);
}
}
g.processed_len += 1;
}
}
process_loop::<F, T, false>(original_len, &mut f, &mut g);
process_loop::<F, T, true>(original_len, &mut f, &mut g);
drop(g);
}
pub fn remove(&mut self, index: u32) -> Result<T, InsertError> {
let len = self.len();
if index >= len {
return Err(IndexOutOfBoundsError.into());
}
let cap = self.buf.capacity();
let ptr = self.buf.as_ptr();
unsafe {
let result = T::from_tuple(T::TupleRepr::read(ptr, index, cap));
if index < len - 1 {
T::TupleRepr::copy(
T::TupleRepr::get_pointers(ptr, index + 1, cap),
T::TupleRepr::get_pointers(ptr, index, cap),
len - index - 1,
);
}
self.buf.set_len(len - 1);
Ok(result)
}
}
pub fn insert(&mut self, index: u32, element: T) -> Result<(), InsertError> {
self.insert_mut(index, element)?;
Ok(())
}
pub fn insert_mut(&mut self, index: u32, element: T) -> Result<T::Mut<'_>, InsertError> {
let len = self.len();
if index > len {
return Err(IndexOutOfBoundsError.into());
}
if len == self.capacity() {
self.buf.reserve(1)?;
}
let ptr = self.buf.as_mut_ptr();
let cap = self.capacity();
unsafe {
if index < len {
let src = T::TupleRepr::get_pointers(ptr, index, cap);
let dst = T::TupleRepr::get_pointers(ptr, (index) + 1, cap);
T::TupleRepr::copy(src, dst, len - (index));
}
let src = T::into_tuple(element);
T::TupleRepr::write(ptr, src, index, cap);
self.buf.set_len(len + 1);
let ptrs = T::TupleRepr::get_pointers(ptr, index, cap);
Ok(T::as_mut(PhantomData, ptrs))
}
}
pub fn clear(&mut self) {
let len = self.len();
if len == 0 {
return;
}
let ptr = self.buf.as_mut_ptr();
let cap = self.capacity();
unsafe {
self.buf.set_len(0);
};
self.drop_in_place(ptr, cap, len);
}
fn drop_in_place(&mut self, ptr: NonNull<u8>, cap: u32, len: u32) {
if T::MUST_DROP_AS_SELF {
for i in 0..len {
let _ = T::from_tuple(unsafe { T::TupleRepr::read(ptr, i, cap) });
}
} else if const { core::mem::needs_drop::<T::TupleRepr>() } {
unsafe { T::TupleRepr::drop_in_place(T::TupleRepr::get_pointers(ptr, 0, cap), len) };
}
}
pub fn swap_remove(&mut self, index: u32) -> Result<T, IndexOutOfBoundsError> {
let len = self.len();
if index >= len {
return Err(IndexOutOfBoundsError);
}
let ptr = self.buf.as_mut_ptr();
let cap = self.capacity();
unsafe {
let value = T::from_tuple(T::TupleRepr::read(ptr, index, cap));
let src = T::TupleRepr::get_pointers(ptr, len - 1, cap);
let dst = T::TupleRepr::get_pointers(ptr, index, cap);
T::TupleRepr::copy(src, dst, 1);
self.buf.set_len(len - 1);
Ok(value)
}
}
}
impl<T: SoAble> Drop for SoAVec<T> {
fn drop(&mut self) {
let len = self.len();
let cap = self.capacity();
let ptr = self.buf.as_mut_ptr();
self.drop_in_place(ptr, cap, len);
}
}
impl<T> PartialEq for SoAVec<T>
where
T: SoAble,
for<'a> T::Slice<'a>: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.as_slice() == other.as_slice()
}
}
impl<T> Eq for SoAVec<T>
where
T: SoAble,
for<'a> T::Slice<'a>: Eq,
{
}
impl<T: SoAble> core::default::Default for SoAVec<T> {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl<T: SoAble> core::fmt::Debug for SoAVec<T>
where
for<'a> T::Slice<'a>: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.as_slice(), f)
}
}
impl<T: SoAble> AsRef<SoAVec<T>> for SoAVec<T> {
#[inline(always)]
fn as_ref(&self) -> &SoAVec<T> {
self
}
}
impl<T: SoAble> AsMut<SoAVec<T>> for SoAVec<T> {
#[inline(always)]
fn as_mut(&mut self) -> &mut SoAVec<T> {
self
}
}
#[cfg(test)]
mod tests {
use core::marker::PhantomData;
use crate as soavec;
use crate::{SoATuple, SoAVec, SoAble};
#[test]
fn basic_usage() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u64,
b: u32,
}
const _ARRAY: [Foo; 16] = [Foo { a: 0, b: 1 }; 16];
const _SOA_ARRAY: ([u64; 16], [u32; 16]) = ([0; 16], [1; 16]);
let mut foo = SoAVec::<Foo>::with_capacity(16).unwrap();
foo.push(Foo { a: 0, b: 2 }).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &0);
assert_eq!(first.b, &2);
let first = foo.get_mut(0).unwrap();
*first.a = 52;
*first.b = 66;
assert_eq!(first.a, &52);
assert_eq!(first.b, &66);
let first = foo.get(0).unwrap();
assert_eq!(first.a, &52);
assert_eq!(first.b, &66);
foo.reserve(32).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &52);
assert_eq!(first.b, &66);
foo.push(Foo { a: 4, b: 8 }).unwrap();
let FooSlice {
a: a_slice,
b: b_slice,
} = foo.as_slice();
assert_eq!(a_slice.len(), b_slice.len());
assert_eq!(a_slice.len(), 2);
assert_eq!(a_slice, &[52, 4]);
assert_eq!(b_slice, &[66, 8]);
assert_eq!(foo.pop(), Some(Foo { a: 4, b: 8 }));
}
#[test]
fn basic_usage_with_lifetime() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Foo<'a> {
a: &'a u64,
b: &'a u32,
}
let mut foo = SoAVec::<Foo>::with_capacity(16).unwrap();
foo.push(Foo { a: &0, b: &2 }).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &&0);
assert_eq!(first.b, &&2);
let first = foo.get_mut(0).unwrap();
*first.a = &52;
*first.b = &66;
assert_eq!(first.a, &&52);
assert_eq!(first.b, &&66);
let first = foo.get(0).unwrap();
assert_eq!(first.a, &&52);
assert_eq!(first.b, &&66);
foo.reserve(32).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &&52);
assert_eq!(first.b, &&66);
foo.push(Foo { a: &4, b: &8 }).unwrap();
let FooSlice {
a: a_slice,
b: b_slice,
} = foo.as_slice();
assert_eq!(a_slice.len(), b_slice.len());
assert_eq!(a_slice.len(), 2);
assert_eq!(a_slice, &[&52, &4]);
assert_eq!(b_slice, &[&66, &8]);
}
#[test]
fn more_basic_usage() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Bar {
a: u64,
b: u32,
c: u8,
}
let mut bar = SoAVec::<Bar>::with_capacity(16).unwrap();
bar.reserve(32).unwrap();
bar.push(Bar { a: 0, b: 2, c: 255 }).unwrap();
let first = bar.get(0).unwrap();
assert_eq!(first.a, &0);
assert_eq!(first.b, &2);
assert_eq!(first.c, &255);
}
#[test]
fn clear_resets_len() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut foo = SoAVec::<Foo>::with_capacity(5).unwrap();
foo.push(Foo { a: 2, b: 0 }).unwrap();
assert_eq!(foo.len(), 1);
foo.clear();
assert_eq!(foo.len(), 0);
foo.push(Foo { a: 3, b: 0 }).unwrap();
assert_eq!(foo.len(), 1);
}
#[test]
fn clear_does_not_change_capacity() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut foo = SoAVec::<Foo>::with_capacity(5).unwrap();
let cap = foo.capacity();
foo.push(Foo { a: 2, b: 0 }).unwrap();
assert_eq!(foo.len(), 1);
assert_eq!(foo.capacity(), cap);
foo.clear();
assert_eq!(foo.len(), 0);
assert_eq!(foo.capacity(), cap);
foo.push(Foo { a: 3, b: 0 }).unwrap();
assert_eq!(foo.len(), 1);
assert_eq!(foo.capacity(), cap);
}
#[test]
fn clears_all_elements() {
use soavec_derive::SoAble;
use std::rc::Rc;
#[repr(C)]
#[derive(Debug, Clone, SoAble)]
struct Foo {
b: Rc<u32>,
a: u64,
}
let rc1 = Rc::new(2u32);
let mut foo = SoAVec::<Foo>::with_capacity(5).unwrap();
foo.push(Foo {
b: rc1.clone(),
a: 0,
})
.unwrap();
assert_eq!(Rc::strong_count(&rc1), 2);
foo.clear();
assert_eq!(foo.len(), 0);
assert_eq!(Rc::strong_count(&rc1), 1);
}
#[test]
fn clears_all_elements_with_droppable() {
#[repr(C)]
struct LoudDrop {
a: (),
b: (),
}
static mut DROP_COUNT: usize = 0;
impl Drop for LoudDrop {
fn drop(&mut self) {
println!("LoudDrop");
unsafe {
DROP_COUNT += 1;
}
}
}
unsafe impl SoAble for LoudDrop {
type TupleRepr = ((), ());
const MUST_DROP_AS_SELF: bool = true;
type Ref<'a>
= (&'a (), &'a ())
where
Self: 'a;
type Mut<'a>
= (&'a mut (), &'a mut ())
where
Self: 'a;
type Slice<'a>
= (&'a [()], &'a [()])
where
Self: 'a;
type SliceMut<'a>
= (&'a mut [()], &'a mut [()])
where
Self: 'a;
fn into_tuple(value: Self) -> Self::TupleRepr {
core::mem::forget(value);
((), ())
}
fn from_tuple(_value: Self::TupleRepr) -> Self {
Self { a: (), b: () }
}
fn as_ref<'a>(
_: PhantomData<&'a Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
) -> Self::Ref<'a> {
unsafe { (value.0.as_ref(), value.1.as_ref()) }
}
fn as_mut<'a>(
_: PhantomData<&'a mut Self>,
mut value: <Self::TupleRepr as SoATuple>::Pointers,
) -> Self::Mut<'a> {
unsafe { (value.0.as_mut(), value.1.as_mut()) }
}
fn as_slice<'a>(
_: PhantomData<&'a Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
len: u32,
) -> Self::Slice<'a> {
unsafe {
(
core::slice::from_raw_parts(value.0.as_ptr(), len as usize),
core::slice::from_raw_parts(value.1.as_ptr(), len as usize),
)
}
}
fn as_mut_slice<'a>(
_: PhantomData<&'a mut Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
len: u32,
) -> Self::SliceMut<'a> {
unsafe {
(
core::slice::from_raw_parts_mut(value.0.as_ptr(), len as usize),
core::slice::from_raw_parts_mut(value.1.as_ptr(), len as usize),
)
}
}
}
let mut foo = SoAVec::<LoudDrop>::with_capacity(16).unwrap();
foo.push(LoudDrop { a: (), b: () }).unwrap();
foo.push(LoudDrop { a: (), b: () }).unwrap();
assert_eq!(foo.len(), 2);
foo.clear();
assert_eq!(foo.len(), 0);
assert_eq!(unsafe { DROP_COUNT }, 2);
}
#[test]
fn basic_usage_with_bad_alignment() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Foo {
b: u32,
a: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Bar {
c: u8,
b: u32,
a: u64,
}
let mut foo = SoAVec::<Foo>::with_capacity(5).unwrap();
foo.reserve(9).unwrap();
foo.push(Foo { b: 2, a: 0 }).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.b, &2);
assert_eq!(first.a, &0);
let mut bar = SoAVec::<Bar>::with_capacity(7).unwrap();
bar.reserve(11).unwrap();
bar.push(Bar { c: 255, b: 2, a: 0 }).unwrap();
let first = bar.get(0).unwrap();
assert_eq!(first.c, &255);
assert_eq!(first.b, &2);
assert_eq!(first.a, &0);
}
#[test]
fn insert_and_insert_mut() {
let mut vec = SoAVec::<(u32, u32)>::new();
vec.push((1, 10)).unwrap();
vec.push((3, 30)).unwrap();
let (first, second) = vec.insert_mut(1, (2, 20)).unwrap();
*first += 10;
*second += 5;
vec.insert(0, (0, 0)).unwrap();
let slice = vec.as_slice();
assert_eq!(slice.0, &[0, 1, 12, 3]);
assert_eq!(slice.1, &[0, 10, 25, 30]);
}
#[test]
fn insert_grows_capacity() {
let mut vec = SoAVec::<(u32, u32)>::with_capacity(2).unwrap();
assert_eq!(vec.capacity(), 2);
vec.push((1, 10)).unwrap();
vec.push((2, 20)).unwrap();
assert_eq!(vec.capacity(), 2);
vec.insert(1, (3, 30)).unwrap();
assert!(vec.capacity() >= 3);
let slice = vec.as_slice();
assert_eq!(slice.0, &[1, 3, 2]);
assert_eq!(slice.1, &[10, 30, 20]);
}
#[test]
fn basic_usage_with_zst() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Foo {
b: (),
a: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Bar {
c: u8,
b: (),
a: u64,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, SoAble)]
struct Baz {
c: (),
b: (),
a: (),
}
let mut foo = SoAVec::<Foo>::with_capacity(5).unwrap();
foo.reserve(9).unwrap();
foo.push(Foo { a: 2, b: () }).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.b, &());
assert_eq!(first.a, &2);
let mut bar = SoAVec::<Bar>::with_capacity(7).unwrap();
bar.reserve(11).unwrap();
bar.push(Bar {
c: 255,
b: (),
a: 0,
})
.unwrap();
let first = bar.get(0).unwrap();
assert_eq!(first.c, &255);
assert_eq!(first.b, &());
assert_eq!(first.a, &0);
let mut baz = SoAVec::<Baz>::with_capacity(7).unwrap();
baz.reserve(11).unwrap();
baz.push(Baz {
a: (),
b: (),
c: (),
})
.unwrap();
let first = baz.get(0).unwrap();
assert_eq!(first.a, &());
assert_eq!(first.b, &());
assert_eq!(first.c, &());
}
#[test]
fn droppable_types() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, SoAble)]
struct Foo {
a: Vec<u64>,
b: Box<u32>,
}
let mut foo = SoAVec::<Foo>::with_capacity(16).unwrap();
foo.push(Foo {
a: vec![0],
b: Box::new(2),
})
.unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &[0]);
assert_eq!(**first.b, 2);
let first = foo.get_mut(0).unwrap();
first.a.push(52);
*first.b = Box::new(66u32);
assert_eq!(first.a, &[0, 52]);
assert_eq!(**first.b, 66u32);
let first = foo.get(0).unwrap();
assert_eq!(first.a, &[0, 52]);
assert_eq!(**first.b, 66u32);
foo.reserve(32).unwrap();
let first = foo.get(0).unwrap();
assert_eq!(first.a, &[0, 52]);
assert_eq!(**first.b, 66u32);
foo.push(Foo {
a: vec![4],
b: Box::new(8),
})
.unwrap();
let FooSlice {
a: a_slice,
b: b_slice,
} = foo.as_slice();
assert_eq!(a_slice.len(), b_slice.len());
assert_eq!(a_slice.len(), 2);
assert_eq!(a_slice, &[vec![0, 52], vec![4]]);
assert_eq!(b_slice, &[Box::new(66), Box::new(8)]);
}
#[test]
fn must_drop_as_self_type() {
#[repr(C)]
struct LoudDrop {
a: (),
b: (),
}
static mut DROP_COUNT: usize = 0;
impl Drop for LoudDrop {
fn drop(&mut self) {
println!("LoudDrop");
unsafe {
DROP_COUNT += 1;
}
}
}
unsafe impl SoAble for LoudDrop {
type TupleRepr = ((), ());
const MUST_DROP_AS_SELF: bool = true;
type Ref<'a>
= (&'a (), &'a ())
where
Self: 'a;
type Mut<'a>
= (&'a mut (), &'a mut ())
where
Self: 'a;
type Slice<'a>
= (&'a [()], &'a [()])
where
Self: 'a;
type SliceMut<'a>
= (&'a mut [()], &'a mut [()])
where
Self: 'a;
fn into_tuple(value: Self) -> Self::TupleRepr {
core::mem::forget(value);
((), ())
}
fn from_tuple(_value: Self::TupleRepr) -> Self {
Self { a: (), b: () }
}
fn as_ref<'a>(
_: PhantomData<&'a Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
) -> Self::Ref<'a> {
unsafe { (value.0.as_ref(), value.1.as_ref()) }
}
fn as_mut<'a>(
_: PhantomData<&'a mut Self>,
mut value: <Self::TupleRepr as SoATuple>::Pointers,
) -> Self::Mut<'a> {
unsafe { (value.0.as_mut(), value.1.as_mut()) }
}
fn as_slice<'a>(
_: PhantomData<&'a Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
len: u32,
) -> Self::Slice<'a> {
unsafe {
(
core::slice::from_raw_parts(value.0.as_ptr(), len as usize),
core::slice::from_raw_parts(value.1.as_ptr(), len as usize),
)
}
}
fn as_mut_slice<'a>(
_: PhantomData<&'a mut Self>,
value: <Self::TupleRepr as SoATuple>::Pointers,
len: u32,
) -> Self::SliceMut<'a> {
unsafe {
(
core::slice::from_raw_parts_mut(value.0.as_ptr(), len as usize),
core::slice::from_raw_parts_mut(value.1.as_ptr(), len as usize),
)
}
}
}
let mut foo = SoAVec::<LoudDrop>::with_capacity(16).unwrap();
foo.push(LoudDrop { a: (), b: () }).unwrap();
let _first = foo.get(0).unwrap();
drop(foo);
assert_eq!(
unsafe { DROP_COUNT },
1,
"should have dropped a single LoudDrop item"
);
}
#[test]
fn remove_at_index() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u64,
b: u32,
}
let mut foo = SoAVec::<Foo>::with_capacity(16).unwrap();
for i in 0..10 {
foo.push(Foo { a: i, b: i as u32 }).unwrap()
}
assert_eq!(foo.len(), 10);
let removed = foo.remove(4).unwrap();
assert_eq!(removed, Foo { a: 4, b: 4 });
assert_eq!(foo.len(), 9);
}
#[test]
fn append_basic() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u64,
b: u32,
}
let mut vec1 = SoAVec::<Foo>::with_capacity(10).unwrap();
vec1.push(Foo { a: 1, b: 2 }).unwrap();
vec1.push(Foo { a: 3, b: 4 }).unwrap();
let mut vec2 = SoAVec::<Foo>::with_capacity(10).unwrap();
vec2.push(Foo { a: 5, b: 6 }).unwrap();
vec2.push(Foo { a: 7, b: 8 }).unwrap();
vec2.push(Foo { a: 9, b: 10 }).unwrap();
let vec2_cap = vec2.capacity();
vec1.append(&mut vec2).unwrap();
assert_eq!(vec1.len(), 5);
assert_eq!(vec2.len(), 0);
assert!(vec2.is_empty());
assert_eq!(vec2.capacity(), vec2_cap);
let elem0 = vec1.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
let elem1 = vec1.get(1).unwrap();
assert_eq!(elem1.a, &3);
assert_eq!(elem1.b, &4);
let elem2 = vec1.get(2).unwrap();
assert_eq!(elem2.a, &5);
assert_eq!(elem2.b, &6);
let elem3 = vec1.get(3).unwrap();
assert_eq!(elem3.a, &7);
assert_eq!(elem3.b, &8);
let elem4 = vec1.get(4).unwrap();
assert_eq!(elem4.a, &9);
assert_eq!(elem4.b, &10);
}
#[test]
fn append_empty_to_non_empty() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut vec1 = SoAVec::<Foo>::new();
vec1.push(Foo { a: 1, b: 2 }).unwrap();
let mut vec2 = SoAVec::<Foo>::new();
vec1.append(&mut vec2).unwrap();
assert_eq!(vec1.len(), 1);
assert_eq!(vec2.len(), 0);
let elem0 = vec1.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
}
#[test]
fn append_non_empty_to_empty() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut vec1 = SoAVec::<Foo>::new();
let mut vec2 = SoAVec::<Foo>::new();
vec2.push(Foo { a: 1, b: 2 }).unwrap();
vec2.push(Foo { a: 3, b: 4 }).unwrap();
vec1.append(&mut vec2).unwrap();
assert_eq!(vec1.len(), 2);
assert_eq!(vec2.len(), 0);
let elem0 = vec1.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
let elem1 = vec1.get(1).unwrap();
assert_eq!(elem1.a, &3);
assert_eq!(elem1.b, &4);
}
#[test]
fn append_with_droppable_types() {
use soavec_derive::SoAble;
use std::rc::Rc;
#[repr(C)]
#[derive(Debug, Clone, SoAble)]
struct Foo {
a: Rc<u64>,
b: Vec<u32>,
}
let mut vec1 = SoAVec::<Foo>::new();
vec1.push(Foo {
a: Rc::new(42),
b: vec![1, 2, 3],
})
.unwrap();
let mut vec2 = SoAVec::<Foo>::new();
let shared_rc = Rc::new(84);
vec2.push(Foo {
a: shared_rc.clone(),
b: vec![4, 5],
})
.unwrap();
vec2.push(Foo {
a: Rc::new(168),
b: vec![6],
})
.unwrap();
assert_eq!(Rc::strong_count(&shared_rc), 2);
vec1.append(&mut vec2).unwrap();
assert_eq!(vec1.len(), 3);
assert_eq!(vec2.len(), 0);
assert_eq!(Rc::strong_count(&shared_rc), 2);
let first = vec1.get(0).unwrap();
assert_eq!(**first.a, 42);
assert_eq!(first.b, &[1, 2, 3]);
let second = vec1.get(1).unwrap();
assert_eq!(**second.a, 84);
assert_eq!(second.b, &[4, 5]);
let third = vec1.get(2).unwrap();
assert_eq!(**third.a, 168);
assert_eq!(third.b, &[6]);
}
#[test]
fn extend_from_slice_basic() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u64,
b: u32,
}
let mut vec = SoAVec::<Foo>::new();
vec.push(Foo { a: 1, b: 2 }).unwrap();
vec.push(Foo { a: 3, b: 4 }).unwrap();
let slice = &[Foo { a: 5, b: 6 }, Foo { a: 7, b: 8 }, Foo { a: 9, b: 10 }];
vec.extend_from_slice(slice).unwrap();
assert_eq!(vec.len(), 5);
let elem0 = vec.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
let elem1 = vec.get(1).unwrap();
assert_eq!(elem1.a, &3);
assert_eq!(elem1.b, &4);
let elem2 = vec.get(2).unwrap();
assert_eq!(elem2.a, &5);
assert_eq!(elem2.b, &6);
let elem3 = vec.get(3).unwrap();
assert_eq!(elem3.a, &7);
assert_eq!(elem3.b, &8);
let elem4 = vec.get(4).unwrap();
assert_eq!(elem4.a, &9);
assert_eq!(elem4.b, &10);
}
#[test]
fn extend_from_slice_empty() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut vec = SoAVec::<Foo>::new();
vec.push(Foo { a: 1, b: 2 }).unwrap();
let empty_slice: &[Foo] = &[];
vec.extend_from_slice(empty_slice).unwrap();
assert_eq!(vec.len(), 1);
let elem0 = vec.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
}
#[test]
fn extend_from_slice_to_empty() {
use soavec_derive::SoAble;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, SoAble)]
struct Foo {
a: u32,
b: u64,
}
let mut vec = SoAVec::<Foo>::new();
let slice = &[Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
vec.extend_from_slice(slice).unwrap();
assert_eq!(vec.len(), 2);
let elem0 = vec.get(0).unwrap();
assert_eq!(elem0.a, &1);
assert_eq!(elem0.b, &2);
let elem1 = vec.get(1).unwrap();
assert_eq!(elem1.a, &3);
assert_eq!(elem1.b, &4);
}
#[test]
fn extend_from_slice_with_droppable_types() {
use soavec_derive::SoAble;
use std::rc::Rc;
#[repr(C)]
#[derive(Debug, Clone, SoAble)]
struct Foo {
a: Rc<u64>,
b: Vec<u32>,
}
let mut vec = SoAVec::<Foo>::new();
vec.push(Foo {
a: Rc::new(42),
b: vec![1, 2, 3],
})
.unwrap();
let shared_rc = Rc::new(84);
let slice = &[
Foo {
a: shared_rc.clone(),
b: vec![4, 5],
},
Foo {
a: Rc::new(168),
b: vec![6],
},
];
assert_eq!(Rc::strong_count(&shared_rc), 2);
vec.extend_from_slice(slice).unwrap();
assert_eq!(vec.len(), 3);
assert_eq!(Rc::strong_count(&shared_rc), 3);
let first = vec.get(0).unwrap();
assert_eq!(**first.a, 42);
assert_eq!(first.b, &[1, 2, 3]);
let second = vec.get(1).unwrap();
assert_eq!(**second.a, 84);
assert_eq!(second.b, &[4, 5]);
let third = vec.get(2).unwrap();
assert_eq!(**third.a, 168);
assert_eq!(third.b, &[6]);
}
}