While safer (and avoids issues with mistakenly deriving SoAble on a type with Drop), it may be less efficient (depending on compiler optimisations) and at the very least more redundant to rely on the SoAble::to_tuple / SoAble::from_tuple methods for moving between T and "T inside SoAVec allocation".
A more optimal but unsafe choice would be a method SoAble::get_field_pointers that takes an exclusive reference to possibly uninitialised T, and returns T::TupleRepr::Pointers pointing at the fields of T. This API can be used to then efficiently either copy data out of T (when moving from T to "T inside SoAVec allocation") field by field, or to initialise the fields of T (when doing the reverse).
fn push(value: T) {
let mut value = MaybeUninit::new(value); // moves value into MU; dropping the MU does not drop `value` anymore.
let field_pointers = unsafe { T::get_field_pointers(&mut value) }; // probably unsafe to do this, gotta think on it
let soa_pointers = T::TupleRepr::get_pointers(self.buf.as_ptr(), self.capacity(), self.len());
T::TupleRepr::copy(field_pointers, soa_pointers, 1); // copy field pointers into soa
}
fn pop() -> Option<T> {
if self.is_empty() {
return None;
}
let mut value: MaybeUninit::uninit();
let field_pointers = T::get_field_pointers(&mut value);
self.set_len(self.len() - 1);
let soa_pointers = T::TupleRepr::get_pointers(self.buf.as_ptr(), self.capacity(), self.len());
T::TupleRepr::copy(soa_pointers, field_pointers, 1); // copy soa pointers into value; this initialises it
Some(value.assume_init())
}
While safer (and avoids issues with mistakenly deriving
SoAbleon a type withDrop), it may be less efficient (depending on compiler optimisations) and at the very least more redundant to rely on theSoAble::to_tuple/SoAble::from_tuplemethods for moving betweenTand "TinsideSoAVecallocation".A more optimal but unsafe choice would be a method
SoAble::get_field_pointersthat takes an exclusive reference to possibly uninitialisedT, and returnsT::TupleRepr::Pointerspointing at the fields ofT. This API can be used to then efficiently either copy data out ofT(when moving fromTto "TinsideSoAVecallocation") field by field, or to initialise the fields ofT(when doing the reverse).