colvec 0.0.4

Struct-of-arrays column vec like Zig's MultiArrayList
Documentation
#![cfg_attr(not(feature = "std"), no_std)]

fn main(){}

// Idea: multi-slice like Vec<T> Derefs to &[T]
// RawColVec Derefs to &RawColSlice
// &RawColSlice has .field1_slice
// RawColVec DerefMuts to &mut RawColSlice
// &mut RawColSlice has .field1_slice_mut
//
// RawColSlice is a ZST but is !Sized to get the fat pointer

#[cfg(test)]
mod tests {
	use ::colvec::*;

	#[cfg(not(feature = "std"))]
	mod global {
		extern crate alloc as core_alloc;
		use core_alloc::alloc::{alloc, dealloc, Layout};
		use core::ptr::NonNull;

		use ::colvec::alloc::{Allocator,AllocError};

		#[derive(Copy, Clone)]
		pub struct Global;

		unsafe impl Allocator for Global {
			#[inline]
			fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
				let non_null=NonNull::new(unsafe{alloc(layout)}).ok_or(AllocError)?;
				Ok(NonNull::slice_from_raw_parts(non_null, layout.size()))
			}
			#[inline]
			unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
				unsafe {dealloc(ptr.as_ptr(), layout) }
			}
		}
		impl Default for Global {
			#[inline]
			fn default() -> Self {
				Global
			}
		}
	}

	#[test]
	fn smoke_test_macro() {
		#[derive(ColVec)]
		struct Test{
			field0:u8,
			field1:i32,
		}

		#[cfg(feature = "std")]
		let mut test=TestColVec::new();
		#[cfg(not(feature = "std"))]
		let mut test=TestColVec::new_in(global::Global);

		test.push(Test{
			field0:255,
			field1:-1,
		});
		test.push(Test{
			field0:1,
			field1:-2,
		});

		test.field0_slice_mut().sort();
		test.field1_slice_mut().sort();

		assert_eq!(&[1,255], test.field0_slice());
		assert_eq!(&[-2,-1], test.field1_slice());
	}

	#[test]
	fn test_zst(){
		#[derive(ColVec)]
		struct ZST{}

		#[cfg(feature = "std")]
		let mut test=ZSTColVec::new();
		#[cfg(not(feature = "std"))]
		let mut test=ZSTColVec::new_in(global::Global);

		test.push(ZST{});
		test.push(ZST{});

		assert_eq!(2, test.len());
	}

	#[test]
	fn test_append() {
		#[derive(ColVec)]
		struct Bug{
			is_red:bool,
			coolness:u64,
		}

		#[cfg(feature = "std")]
		let mut bugs=BugColVec::with_capacity(2);
		#[cfg(not(feature = "std"))]
		let mut bugs=BugColVec::with_capacity_in(2,global::Global);
		bugs.push(Bug{
			is_red:false,
			coolness:1,
		});

		#[cfg(feature = "std")]
		let mut cool_bugs=BugColVec::with_capacity(1);
		#[cfg(not(feature = "std"))]
		let mut cool_bugs=BugColVec::with_capacity_in(1,global::Global);
		cool_bugs.push(Bug{
			is_red:true,
			coolness:1337,
		});

		bugs.append(&mut cool_bugs);

		assert_eq!(&[false,true], bugs.is_red_slice());
		assert_eq!(&[1,1337], bugs.coolness_slice());
	}

	#[test]
	fn test_clone() {
		#[derive(ColVec)]
		struct Test{
			field0:u8,
			field1:i32,
		}

		#[cfg(feature = "std")]
		let mut test=TestColVec::new();
		#[cfg(not(feature = "std"))]
		let mut test=TestColVec::new_in(global::Global);

		// cloning an empty colvec works
		assert_eq!(0, test.clone().len());

		// len=9 grows the original to capacity 16, while the clone is
		// allocated with the exact capacity 12 (a multiple of the align 4)
		for i in 0..9 {
			test.push(Test{
				field0:i as u8,
				field1:i as i32,
			});
		}

		let mut cloned=test.clone();

		assert_eq!(9, cloned.len());
		assert_eq!(test.field0_slice(), cloned.field0_slice());
		assert_eq!(test.field1_slice(), cloned.field1_slice());

		// the clone is independent of the original
		cloned.push(Test{
			field0:255,
			field1:-1,
		});
		assert_eq!(9, test.len());
		assert_eq!(10, cloned.len());
	}

	#[test]
	fn test_clone_zst() {
		#[derive(ColVec)]
		struct ZST{}

		#[cfg(feature = "std")]
		let mut test=ZSTColVec::new();
		#[cfg(not(feature = "std"))]
		let mut test=ZSTColVec::new_in(global::Global);

		test.push(ZST{});
		test.push(ZST{});

		let cloned=test.clone();

		assert_eq!(2, cloned.len());
	}
}