use std::marker::PhantomData;
use std::mem::size_of;
fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
let mut v = Vec::with_capacity(rounded_size);
for _ in 0..rounded_size {
v.push(T::default())
}
v
}
pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
let element_space = count * size_of::<F>();
let vec_size_bytes = size_of::<T>() + element_space;
vec_with_size_in_bytes(vec_size_bytes)
}
pub trait FlexibleArray<S> {
fn set_len(&mut self, len: usize);
fn get_len(&self) -> usize;
unsafe fn get_slice(&self, len: usize) -> &[S];
unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [S];
}
#[macro_export]
macro_rules! flexible_array_impl {
($T:ident, $S:ident, $nents:ident, $entries:ident) => {
impl $crate::FlexibleArray<$S> for $T {
fn set_len(&mut self, len: usize) {
self.$nents = ::std::convert::TryInto::try_into(len).unwrap();
}
fn get_len(&self) -> usize {
self.$nents as usize
}
unsafe fn get_slice(&self, len: usize) -> &[$S] {
self.$entries.as_slice(len)
}
unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [$S] {
self.$entries.as_mut_slice(len)
}
}
};
}
pub struct FlexibleArrayWrapper<T, S> {
entries: Vec<T>,
phantom: PhantomData<S>,
allocated_len: usize,
}
impl<T, S> FlexibleArrayWrapper<T, S>
where
T: FlexibleArray<S> + Default,
{
pub fn new(array_len: usize) -> FlexibleArrayWrapper<T, S> {
let mut entries = vec_with_array_field::<T, S>(array_len);
entries[0].set_len(array_len);
FlexibleArrayWrapper {
entries,
phantom: PhantomData,
allocated_len: array_len,
}
}
fn get_valid_len(&self) -> usize {
if self.entries[0].get_len() > self.allocated_len {
self.allocated_len
} else {
self.entries[0].get_len()
}
}
pub fn entries_slice(&self) -> &[S] {
let valid_length = self.get_valid_len();
unsafe { self.entries[0].get_slice(valid_length) }
}
pub fn mut_entries_slice(&mut self) -> &mut [S] {
let valid_length = self.get_valid_len();
self.entries[0].set_len(valid_length);
unsafe { self.entries[0].get_mut_slice(valid_length) }
}
pub fn as_ptr(&self) -> *const T {
&self.entries[0]
}
pub fn as_mut_ptr(&mut self) -> *mut T {
&mut self.entries[0]
}
}