From 5a7da770478646ac85f14f49af77c7afc1377cec Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 25 Mar 2025 15:30:50 +0100 Subject: feat: allow for dynamic fields --- src/lib.rs | 751 ++++++++++++++++++++++++++----------------------------------- 1 file changed, 324 insertions(+), 427 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 6b1a2e4..de7afe4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,55 @@ #![deny(clippy::all, clippy::pedantic)] -use std::alloc::{alloc, handle_alloc_error, realloc, Layout}; +use std::alloc::{alloc, dealloc, handle_alloc_error, realloc, Layout}; +use std::any::Any; use std::cmp::max; -use std::marker::PhantomData; -use std::mem::{forget, needs_drop}; use std::ptr::NonNull; +pub struct OwnedAnyPtr +{ + ptr: *mut dyn Any, +} + +impl OwnedAnyPtr +{ + pub fn new(value: Value) -> Self + { + Self::from_boxed(Box::new(value)) + } + + pub fn from_boxed(boxed_value: Box) -> Self + { + Self { ptr: Box::into_raw(boxed_value) } + } + + pub fn as_ptr(&self) -> *const dyn Any + { + self.ptr + } + + pub fn size(&self) -> usize + { + size_of_val(unsafe { &*self.ptr }) + } + + pub fn alignment(&self) -> usize + { + align_of_val(unsafe { &*self.ptr }) + } +} + +impl Drop for OwnedAnyPtr +{ + fn drop(&mut self) + { + unsafe { + dealloc( + self.ptr.cast::(), + Layout::from_size_align(self.size(), self.alignment()).unwrap(), + ); + } + } +} + /// A list of `ItemT`. This data structure stores a list for every field of `ItemT`, /// reducing memory usage if `ItemT` contains padding and improves memory cache usage if /// only certain fields are needed when iterating. @@ -28,68 +73,72 @@ use std::ptr::NonNull; /// age, age, age, /// ``` #[derive(Debug)] -pub struct MultiVec -where - ItemT: Item, +pub struct MultiVec { - _pd: PhantomData, ptr: NonNull, field_arr_byte_offsets: Vec, + field_sizes: Vec, length: usize, capacity: usize, layout: Option, } -impl MultiVec -where - ItemT: Item, +impl MultiVec { - // The following is borrow from std's RawVec implementation: - // Skip to: - // - 8 if the element size is 1, because any heap allocators is likely to round up a - // request of less than 8 bytes to at least 8 bytes. - // - 4 if elements are moderate-sized (<= 1 KiB). - // - 1 otherwise, to avoid wasting too much space for very short Vecs. - const MIN_NON_ZERO_CAP: usize = if size_of::() == 1 { - 8 - } else if size_of::() <= 1024 { - 4 - } else { - 1 - }; + fn get_min_non_zero_cap(fields: impl AsRef<[OwnedAnyPtr]>) -> usize + { + let total_size = fields + .as_ref() + .iter() + .fold(0usize, |acc, field| acc + field.size()); + + // The following is borrow from std's RawVec implementation: + // Skip to: + // - 8 if the element size is 1, because any heap allocators is likely to round up + // a request of less than 8 bytes to at least 8 bytes. + // - 4 if elements are moderate-sized (<= 1 KiB). + // - 1 otherwise, to avoid wasting too much space for very short Vecs. + if total_size == 1 { + 8 + } else if total_size <= 1024 { + 4 + } else { + 1 + } + } /// Returns a new `MultiVec`. This function does not allocate any memory. #[must_use] pub const fn new() -> Self { Self { - _pd: PhantomData, ptr: NonNull::dangling(), field_arr_byte_offsets: Vec::new(), + field_sizes: Vec::new(), length: 0, capacity: 0, layout: None, } } - /// Returns a new `MultiVec` with a capacity for `capacity` items. This function will - /// allocate memory. - #[must_use] - pub fn with_capacity(capacity: usize) -> Self - { - let mut this = Self { - _pd: PhantomData, - ptr: NonNull::dangling(), - field_arr_byte_offsets: Vec::new(), - length: 0, - capacity: 0, - layout: None, - }; - - this.do_first_alloc(capacity); - - this - } + ///// Returns a new `MultiVec` with a capacity for `capacity` items. This function + ///// will allocate memory. + //#[must_use] + //pub fn with_capacity(capacity: usize) -> Self + //{ + // let mut this = Self { + // _pd: PhantomData, + // ptr: NonNull::dangling(), + // field_arr_byte_offsets: Vec::new(), + // length: 0, + // capacity: 0, + // layout: None, + // }; + // + // this.do_first_alloc(capacity); + // + // this + //} /// Pushes a item to the `MultiVec`. /// @@ -97,60 +146,63 @@ where /// Pushing can be pretty slow. Since all of the field lists are stored in the same /// allocation, when pushing and the `MultiVec` needs to grow, all lists except the /// first has to be moved to new locations for them to not overlap. - pub fn push(&mut self, item: ItemT) + pub fn push( + &mut self, + fields: impl AsRef<[OwnedAnyPtr]> + IntoIterator, + ) { if self.capacity != 0 { if self.capacity == self.length { - self.grow_amortized(1); + self.grow_amortized(1, &fields); } - self.write_item(self.length, item); + self.write_item(self.length, fields); self.length += 1; return; } - self.do_first_alloc(1); + self.field_sizes = fields.as_ref().iter().map(|field| field.size()).collect(); + + self.do_first_alloc(1, &fields); - self.write_item(0, item); + self.write_item(0, fields); self.length = 1; } - /// Returns a field of the item with the given index. - /// - /// This function is equivalant to doing `.get_all().get(index)` - #[must_use] - pub fn get( - &self, - index: usize, - ) -> Option<&>::Field> - where - FieldSel: ItemFieldSelection, - { - if index >= self.length { - return None; - } - - let field_metadata = FieldSel::metadata(); - - let field_arr_byte_offset = self.field_arr_byte_offsets[FieldSel::INDEX]; - - let field_arr_ptr = unsafe { self.ptr.byte_add(field_arr_byte_offset) }; - - let field_ptr = unsafe { field_arr_ptr.add(field_metadata.size * index) }; - - Some(unsafe { field_ptr.cast().as_ref() }) - } + ///// Returns a field of the item with the given index. + ///// + ///// This function is equivalant to doing `.get_all().get(index)` + //#[must_use] + //pub fn get( + // &self, + // index: usize, + //) -> Option<&>::Field> + //where + // FieldSel: ItemFieldSelection, + //{ + // if index >= self.length { + // return None; + // } + // + // let field_metadata = FieldSel::metadata(); + // + // let field_arr_byte_offset = self.field_arr_byte_offsets[FieldSel::INDEX]; + // + // let field_arr_ptr = unsafe { self.ptr.byte_add(field_arr_byte_offset) }; + // + // let field_ptr = unsafe { field_arr_ptr.add(field_metadata.size * index) }; + // + // Some(unsafe { field_ptr.cast().as_ref() }) + //} /// Returns a slice containing the specified field of all items. #[must_use] - pub fn get_all(&self) -> &[>::Field] - where - FieldSel: ItemFieldSelection, + pub fn get_all(&self, field_index: usize) -> &[()] { - let field_arr_byte_offset = self.field_arr_byte_offsets[FieldSel::INDEX]; + let field_arr_byte_offset = self.field_arr_byte_offsets[field_index]; let field_arr_ptr = unsafe { self.ptr.byte_add(field_arr_byte_offset) }; @@ -178,18 +230,19 @@ where self.length == 0 } - fn grow_amortized(&mut self, additional: usize) + fn grow_amortized(&mut self, additional: usize, fields: impl AsRef<[OwnedAnyPtr]>) { let required_cap = self.capacity.checked_add(additional).unwrap(); // This guarantees exponential growth. The doubling cannot overflow // because `cap <= isize::MAX` and the type of `cap` is `usize`. let new_capacity = max(self.capacity * 2, required_cap); - let new_capacity = max(Self::MIN_NON_ZERO_CAP, new_capacity); + let new_capacity = max(Self::get_min_non_zero_cap(&fields), new_capacity); let layout = &self.layout.unwrap(); - let (new_layout, new_field_arr_byte_offsets) = Self::create_layout(new_capacity); + let (new_layout, new_field_arr_byte_offsets) = + Self::create_layout(new_capacity, &fields); let Some(new_ptr) = NonNull::new(unsafe { realloc(self.ptr.as_ptr(), *layout, new_layout.size()) @@ -197,9 +250,7 @@ where handle_alloc_error(new_layout); }; - for (field_index, field_metadata) in - ItemT::iter_field_metadata().enumerate().rev() - { + for (field_index, field) in fields.as_ref().iter().enumerate().rev() { let old_field_arr_byte_offset = self.field_arr_byte_offsets[field_index]; let new_field_arr_byte_offset = new_field_arr_byte_offsets[field_index]; @@ -213,7 +264,7 @@ where std::ptr::copy( old_field_arr_ptr.as_ptr(), new_field_arr_ptr.as_ptr(), - field_metadata.size * self.capacity, + field.size() * self.capacity, ); } } @@ -224,9 +275,9 @@ where self.field_arr_byte_offsets = new_field_arr_byte_offsets; } - fn do_first_alloc(&mut self, capacity: usize) + fn do_first_alloc(&mut self, capacity: usize, fields: impl AsRef<[OwnedAnyPtr]>) { - let (layout, field_arr_byte_offsets) = Self::create_layout(capacity); + let (layout, field_arr_byte_offsets) = Self::create_layout(capacity, fields); let Some(ptr) = NonNull::new(unsafe { alloc(layout) }) else { handle_alloc_error(layout); @@ -238,29 +289,25 @@ where self.layout = Some(layout); } - fn create_layout(length: usize) -> (Layout, Vec) + fn create_layout( + length: usize, + fields: impl AsRef<[OwnedAnyPtr]>, + ) -> (Layout, Vec) { - let mut field_metadata_iter = ItemT::iter_field_metadata(); + let mut field_iter = fields.as_ref().iter(); - let first_field_metadata = field_metadata_iter.next().unwrap(); + let first_field = field_iter.next().unwrap(); - let mut layout = array_layout( - first_field_metadata.size, - first_field_metadata.alignment, - length, - ) - .unwrap(); + let mut layout = + array_layout(first_field.size(), first_field.alignment(), length).unwrap(); - let mut field_arr_byte_offsets = Vec::with_capacity(ItemT::FIELD_CNT); + let mut field_arr_byte_offsets = Vec::with_capacity(fields.as_ref().len()); field_arr_byte_offsets.push(0); - for field_metadata in field_metadata_iter { + for field in field_iter { let (new_layout, array_byte_offset) = layout - .extend( - array_layout(field_metadata.size, field_metadata.alignment, length) - .unwrap(), - ) + .extend(array_layout(field.size(), field.alignment(), length).unwrap()) .unwrap(); layout = new_layout; @@ -271,60 +318,58 @@ where (layout, field_arr_byte_offsets) } - fn write_item(&mut self, index: usize, item: ItemT) + fn write_item(&mut self, index: usize, fields: impl IntoIterator) { - for (field_index, field_metadata) in ItemT::iter_field_metadata().enumerate() { + for (field_index, item_field) in fields.into_iter().enumerate() { + let field_size = item_field.size(); + let field_arr_byte_offset = self.field_arr_byte_offsets[field_index]; let field_arr_ptr = unsafe { self.ptr.byte_add(field_arr_byte_offset) }; - let field_ptr = unsafe { field_arr_ptr.add(field_metadata.size * index) }; + let field_dst_ptr = unsafe { field_arr_ptr.add(field_size * index) }; + + let item_field_ptr = item_field.as_ptr().cast::(); unsafe { std::ptr::copy_nonoverlapping( - std::ptr::from_ref(&item) - .byte_add(field_metadata.offset) - .cast::(), - field_ptr.as_ptr(), - field_metadata.size, + item_field_ptr, + field_dst_ptr.as_ptr(), + field_size, ); } } - - forget(item); - } -} - -impl FromIterator for MultiVec -where - ItemT: Item, -{ - fn from_iter>(iter: ItemIter) -> Self - { - let iter = iter.into_iter(); - - let initial_capacity = - max(Self::MIN_NON_ZERO_CAP, iter.size_hint().0.saturating_add(1)); - - let mut this = Self::with_capacity(initial_capacity); - - for item in iter { - if this.capacity == this.length { - this.grow_amortized(1); - } - - this.write_item(this.length, item); - - this.length += 1; - } - - this } } -impl Default for MultiVec -where - ItemT: Item, +//impl FromIterator for MultiVec +//where +// ItemT: Item, +//{ +// fn from_iter>(iter: ItemIter) -> Self +// { +// let iter = iter.into_iter(); +// +// let initial_capacity = +// max(Self::MIN_NON_ZERO_CAP, iter.size_hint().0.saturating_add(1)); +// +// let mut this = Self::with_capacity(initial_capacity); +// +// for item in iter { +// if this.capacity == this.length { +// this.grow_amortized(1); +// } +// +// this.write_item(this.length, item); +// +// this.length += 1; +// } +// +// this +// } +//} + +impl Default for MultiVec { fn default() -> Self { @@ -332,29 +377,27 @@ where } } -impl Drop for MultiVec -where - ItemT: Item, +impl Drop for MultiVec { fn drop(&mut self) { - if needs_drop::() { - for index in 0..self.length { - for (field_index, field_metadata) in - ItemT::iter_field_metadata().enumerate() - { - let field_arr_byte_offset = self.field_arr_byte_offsets[field_index]; - - let field_arr_ptr = - unsafe { self.ptr.byte_add(field_arr_byte_offset) }; - - let field_ptr = - unsafe { field_arr_ptr.add(field_metadata.size * index) }; - - unsafe { - ItemT::drop_field_inplace(field_index, field_ptr.as_ptr()); - } + assert_eq!(self.field_sizes.len(), self.field_arr_byte_offsets.len()); + + for index in 0..self.length { + for (field_index, field_size) in self.field_sizes.iter().enumerate() { + let field_arr_byte_offset = self.field_arr_byte_offsets[field_index]; + + let field_arr_ptr = unsafe { self.ptr.byte_add(field_arr_byte_offset) }; + + let field_ptr = unsafe { field_arr_ptr.add(field_size * index) }; + + unsafe { + field_ptr.drop_in_place(); } + + //unsafe { + // ItemT::drop_field_inplace(field_index, field_ptr.as_ptr()); + //} } } @@ -366,93 +409,6 @@ where } } -/// Usable as a item of a [`MultiVec`]. -/// -/// # Safety -/// The iterator returned by `iter_field_metadata` must yield [`ItemFieldMetadata`] that -/// correctly represents fields of the implementor type. -pub unsafe trait Item -{ - type FieldMetadataIter<'a>: Iterator - + DoubleEndedIterator - + ExactSizeIterator; - - /// The number of fields this item has. - const FIELD_CNT: usize; - - /// Returns a iterator of metadata of the fields of this item. - fn iter_field_metadata() -> Self::FieldMetadataIter<'static>; - - /// Drops a field of this item inplace. - /// - /// # Safety - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `field_index` must be a valid field index for this item. - /// * The value `field_ptr` points to must be valid for the type of the field with - /// index `field_index`. - /// * `field_ptr` must be [valid] for both reads and writes. - /// * `field_ptr` must be properly aligned, even if the field type has size 0. - /// * `field_ptr` must be nonnull, even if the field type has size 0. - /// * The value `field_ptr` points to must be valid for dropping, which may mean it - /// must uphold additional invariants. These invariants depend on the type of the - /// value being dropped. For instance, when dropping a Box, the box's pointer to the - /// heap must be valid. - /// * While `drop_field_inplace` is executing, the only way to access parts of - /// `field_ptr` is through the `&mut self` references supplied to the [`Drop::drop`] - /// methods that `drop_field_inplace` invokes. - /// - /// Additionally, if the field type is not [`Copy`], using the pointed-to value after - /// calling `drop_field_inplace` can cause undefined behavior. Note that `*field_ptr = - /// foo` counts as a use because it will cause the value to be dropped again. - /// - /// [valid]: https://doc.rust-lang.org/std/ptr/index.html#safety - unsafe fn drop_field_inplace(field_index: usize, field_ptr: *mut u8); -} - -/// Contains metadata of a field of a [`Item`]. -/// -/// # Examples -/// ``` -/// # use multi_vec::ItemFieldMetadata; -/// # -/// struct CatFood -/// { -/// label: String, -/// age_days: u16, -/// quality: u8, -/// } -/// -/// let cat_food_field_metadata = ItemFieldMetadata { -/// offset: std::mem::offset_of!(CatFood, age_days), -/// size: std::mem::size_of::(), -/// alignment: std::mem::align_of::(), -/// }; -/// ``` -pub struct ItemFieldMetadata -{ - pub offset: usize, - pub size: usize, - pub alignment: usize, -} - -/// A field selection for `ItemT`. -/// -/// # Safety -/// The constant `INDEX`, the type `Field` and the `ItemFieldMetadata` returned by the -/// `metadata` function must correctly represent a field of `ItemT`; -pub unsafe trait ItemFieldSelection -where - ItemT: Item, -{ - const INDEX: usize; - - type Field; - - /// Returns metadata of this item field. - fn metadata() -> &'static ItemFieldMetadata; -} - #[inline] const fn array_layout( element_size: usize, @@ -509,84 +465,16 @@ struct CoolLayoutError; #[cfg(test)] mod tests { - use std::mem::offset_of; - use std::ptr::{drop_in_place, NonNull}; - - use crate::{Item, ItemFieldMetadata, ItemFieldSelection, MultiVec}; - - struct Foo - { - num_a: u32, - num_b: u16, - } - - struct FooFieldNumA; - struct FooFieldNumB; - - unsafe impl ItemFieldSelection for FooFieldNumA - { - type Field = u32; - - const INDEX: usize = 0; - - fn metadata() -> &'static ItemFieldMetadata - { - &FOO_FIELD_METADATA[0] - } - } - - unsafe impl ItemFieldSelection for FooFieldNumB - { - type Field = u16; - - const INDEX: usize = 1; - - fn metadata() -> &'static ItemFieldMetadata - { - &FOO_FIELD_METADATA[1] - } - } - - static FOO_FIELD_METADATA: [ItemFieldMetadata; 2] = [ - ItemFieldMetadata { - offset: offset_of!(Foo, num_a), - size: size_of::(), - alignment: align_of::(), - }, - ItemFieldMetadata { - offset: offset_of!(Foo, num_b), - size: size_of::(), - alignment: align_of::(), - }, - ]; - - unsafe impl Item for Foo - { - type FieldMetadataIter<'a> = std::slice::Iter<'a, ItemFieldMetadata>; - - const FIELD_CNT: usize = 2; + use std::ptr::NonNull; - fn iter_field_metadata() -> Self::FieldMetadataIter<'static> - { - FOO_FIELD_METADATA.iter() - } - - unsafe fn drop_field_inplace(field_index: usize, field_ptr: *mut u8) - { - if field_index == 0 { - unsafe { drop_in_place::(field_ptr.cast()) } - } else if field_index == 1 { - unsafe { drop_in_place::(field_ptr.cast()) } - } - } - } + use crate::{MultiVec, OwnedAnyPtr}; #[test] fn single_push_works() { - let mut multi_vec = MultiVec::::new(); + let mut multi_vec = MultiVec::new(); - multi_vec.push(Foo { num_a: 123, num_b: 654 }); + multi_vec.push([OwnedAnyPtr::new(123), OwnedAnyPtr::new(654)]); assert_eq!(multi_vec.capacity, 1); assert_eq!(multi_vec.length, 1); @@ -614,11 +502,11 @@ mod tests #[test] fn multiple_pushes_works() { - let mut multi_vec = MultiVec::::new(); + let mut multi_vec = MultiVec::new(); - multi_vec.push(Foo { num_a: u32::MAX / 2, num_b: 654 }); - multi_vec.push(Foo { num_a: 765, num_b: u16::MAX / 3 }); - multi_vec.push(Foo { num_a: u32::MAX / 5, num_b: 337 }); + multi_vec.push([OwnedAnyPtr::new(u32::MAX / 2), OwnedAnyPtr::new::(654)]); + multi_vec.push([OwnedAnyPtr::new(765), OwnedAnyPtr::new::(u16::MAX / 3)]); + multi_vec.push([OwnedAnyPtr::new(u32::MAX / 5), OwnedAnyPtr::new::(337)]); assert_eq!(multi_vec.capacity, 4); assert_eq!(multi_vec.length, 3); @@ -643,134 +531,143 @@ mod tests ); } - #[test] - fn multiple_pushes_in_preallocated_works() - { - let mut multi_vec = MultiVec::::with_capacity(2); - - multi_vec.push(Foo { num_a: 83710000, num_b: 654 }); - multi_vec.push(Foo { num_a: 765, num_b: u16::MAX / 7 }); - - assert_eq!(multi_vec.capacity, 2); - assert_eq!(multi_vec.length, 2); - - assert_eq!(multi_vec.field_arr_byte_offsets, [0, size_of::() * 2]); - - assert_eq!( - unsafe { - std::slice::from_raw_parts::(multi_vec.ptr.as_ptr().cast(), 2) - }, - [83710000, 765] - ); - - assert_eq!( - unsafe { - std::slice::from_raw_parts::( - multi_vec.ptr.as_ptr().byte_add(size_of::() * 2).cast(), - 2, - ) - }, - [654, u16::MAX / 7] - ); - } - - #[test] - fn get_works() + //#[test] + //fn multiple_pushes_in_preallocated_works() + //{ + // let mut multi_vec = MultiVec::::with_capacity(2); + // + // multi_vec.push(Foo { num_a: 83710000, num_b: 654 }); + // multi_vec.push(Foo { num_a: 765, num_b: u16::MAX / 7 }); + // + // assert_eq!(multi_vec.capacity, 2); + // assert_eq!(multi_vec.length, 2); + // + // assert_eq!(multi_vec.field_arr_byte_offsets, [0, size_of::() * 2]); + // + // assert_eq!( + // unsafe { + // std::slice::from_raw_parts::(multi_vec.ptr.as_ptr().cast(), 2) + // }, + // [83710000, 765] + // ); + // + // assert_eq!( + // unsafe { + // std::slice::from_raw_parts::( + // multi_vec.ptr.as_ptr().byte_add(size_of::() * 2).cast(), + // 2, + // ) + // }, + // [654, u16::MAX / 7] + // ); + //} + + //#[test] + //fn get_works() + //{ + // let mut multi_vec = MultiVec::::new(); + // + // #[repr(packed)] + // #[allow(dead_code)] + // struct Data + // { + // num_a: [u32; 3], + // num_b: [u16; 3], + // } + // + // let data = Data { + // num_a: [u32::MAX - 3000, 901, 5560000], + // num_b: [20210, 7120, 1010], + // }; + // + // multi_vec.ptr = NonNull::from(&data).cast(); + // multi_vec.field_arr_byte_offsets = vec![0, size_of::() * 3]; + // multi_vec.length = 3; + // multi_vec.capacity = 3; + // + // assert_eq!( + // multi_vec.get::(0).copied(), + // Some(u32::MAX - 3000) + // ); + // assert_eq!(multi_vec.get::(0).copied(), Some(20210)); + // + // assert_eq!(multi_vec.get::(1).copied(), Some(901)); + // assert_eq!(multi_vec.get::(1).copied(), Some(7120)); + // + // assert_eq!(multi_vec.get::(2).copied(), Some(5560000)); + // assert_eq!(multi_vec.get::(2).copied(), Some(1010)); + //} + + //#[test] + //fn from_iter_works() + //{ + // let multi_vec = MultiVec::::from_iter([ + // Foo { num_a: 456456, num_b: 9090 }, + // Foo { num_a: 79541, num_b: 2233 }, + // Foo { num_a: 1761919, num_b: u16::MAX - 75 }, + // Foo { num_a: u32::MAX / 9, num_b: 8182 }, + // ]); + // + // assert_eq!(multi_vec.length, 4); + // assert_eq!(multi_vec.capacity, 5); + // + // assert_eq!(multi_vec.field_arr_byte_offsets, [0, size_of::() * 5]); + // + // assert_eq!( + // unsafe { + // std::slice::from_raw_parts::(multi_vec.ptr.as_ptr().cast(), 4) + // }, + // [456456, 79541, 1761919, u32::MAX / 9] + // ); + // + // assert_eq!( + // unsafe { + // std::slice::from_raw_parts::( + // multi_vec.ptr.as_ptr().byte_add(size_of::() * 5).cast(), + // 4, + // ) + // }, + // [9090, 2233, u16::MAX - 75, 8182] + // ); + //} + + unsafe fn cast_slice(slice: &[SrcItem]) -> &[DstItem] { - let mut multi_vec = MultiVec::::new(); - - #[repr(packed)] - #[allow(dead_code)] - struct Data - { - num_a: [u32; 3], - num_b: [u16; 3], + unsafe { + std::slice::from_raw_parts(slice.as_ptr().cast::(), slice.len()) } - - let data = Data { - num_a: [u32::MAX - 3000, 901, 5560000], - num_b: [20210, 7120, 1010], - }; - - multi_vec.ptr = NonNull::from(&data).cast(); - multi_vec.field_arr_byte_offsets = vec![0, size_of::() * 3]; - multi_vec.length = 3; - multi_vec.capacity = 3; - - assert_eq!( - multi_vec.get::(0).copied(), - Some(u32::MAX - 3000) - ); - assert_eq!(multi_vec.get::(0).copied(), Some(20210)); - - assert_eq!(multi_vec.get::(1).copied(), Some(901)); - assert_eq!(multi_vec.get::(1).copied(), Some(7120)); - - assert_eq!(multi_vec.get::(2).copied(), Some(5560000)); - assert_eq!(multi_vec.get::(2).copied(), Some(1010)); - } - - #[test] - fn from_iter_works() - { - let multi_vec = MultiVec::::from_iter([ - Foo { num_a: 456456, num_b: 9090 }, - Foo { num_a: 79541, num_b: 2233 }, - Foo { num_a: 1761919, num_b: u16::MAX - 75 }, - Foo { num_a: u32::MAX / 9, num_b: 8182 }, - ]); - - assert_eq!(multi_vec.length, 4); - assert_eq!(multi_vec.capacity, 5); - - assert_eq!(multi_vec.field_arr_byte_offsets, [0, size_of::() * 5]); - - assert_eq!( - unsafe { - std::slice::from_raw_parts::(multi_vec.ptr.as_ptr().cast(), 4) - }, - [456456, 79541, 1761919, u32::MAX / 9] - ); - - assert_eq!( - unsafe { - std::slice::from_raw_parts::( - multi_vec.ptr.as_ptr().byte_add(size_of::() * 5).cast(), - 4, - ) - }, - [9090, 2233, u16::MAX - 75, 8182] - ); } #[test] fn get_all_works() { - let mut multi_vec = MultiVec::::new(); + let mut multi_vec = MultiVec::new(); - #[repr(packed)] - #[allow(dead_code)] struct Data { - num_a: [u32; 3], - num_b: [u16; 3], + _a: [u32; 3], + _b: [u16; 3], } let data = Data { - num_a: [u32::MAX - 3000, 901, 5560000], - num_b: [20210, 7120, 1010], + _a: [u32::MAX - 3000, 901, 5560000], + _b: [20210, 7120, 1010], }; multi_vec.ptr = NonNull::from(&data).cast(); multi_vec.field_arr_byte_offsets = vec![0, size_of::() * 3]; + multi_vec.field_sizes = vec![size_of::(), size_of::()]; multi_vec.length = 3; multi_vec.capacity = 3; assert_eq!( - multi_vec.get_all::(), + unsafe { cast_slice::<_, u32>(multi_vec.get_all(0)) }, [u32::MAX - 3000, 901, 5560000] ); - assert_eq!(multi_vec.get_all::(), [20210, 7120, 1010]); + assert_eq!( + unsafe { cast_slice::<_, u16>(multi_vec.get_all(1)) }, + [20210, 7120, 1010] + ); } } -- cgit v1.2.3-18-g5258