From 0f51ae2df6b8101297fce8540cdc51166c34482b Mon Sep 17 00:00:00 2001
From: HampusM <hampus@hampusmat.com>
Date: Mon, 26 Aug 2024 19:29:25 +0200
Subject: feat: add support for containing more than 1 item

---
 src/lib.rs | 98 ++++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 66 insertions(+), 32 deletions(-)

(limited to 'src')

diff --git a/src/lib.rs b/src/lib.rs
index 998da2e..098d726 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,4 @@
-use std::alloc::{alloc, handle_alloc_error, Layout};
+use std::alloc::{alloc, handle_alloc_error, realloc, Layout};
 use std::marker::PhantomData;
 use std::mem::{forget, needs_drop};
 use std::ptr::NonNull;
@@ -55,15 +55,13 @@ where
     pub fn push(&mut self, item: ItemT)
     {
         if self.length != 0 {
-            todo!();
-        }
+            self.reallocate_for_more(1);
 
-        let (ptr, fields_arr_byte_offsets, layout) = Self::do_first_alloc();
+            self.write_item(self.length - 1, item);
+            return;
+        }
 
-        self.ptr = ptr;
-        self.length = 1;
-        self.field_arr_byte_offsets = fields_arr_byte_offsets;
-        self.layout = Some(layout);
+        self.do_first_alloc();
 
         self.write_item(0, item);
     }
@@ -93,7 +91,48 @@ where
         unsafe { field_ptr.cast().as_ref() }
     }
 
-    fn do_first_alloc() -> (NonNull<u8>, Vec<usize>, Layout)
+    fn reallocate_for_more(&mut self, item_cnt_inc: usize)
+    {
+        let new_length = self.length + item_cnt_inc;
+
+        let layout = &self.layout.unwrap();
+
+        let (new_layout, new_field_arr_byte_offsets) = Self::create_layout(new_length);
+
+        let Some(new_ptr) = NonNull::new(unsafe {
+            realloc(self.ptr.as_ptr(), *layout, new_layout.size())
+        }) else {
+            handle_alloc_error(new_layout);
+        };
+
+        for (field_index, field_metadata) in
+            ItemT::iter_field_metadata().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];
+
+            let old_field_arr_ptr =
+                unsafe { new_ptr.byte_add(old_field_arr_byte_offset) };
+
+            let new_field_arr_ptr =
+                unsafe { new_ptr.byte_add(new_field_arr_byte_offset) };
+
+            unsafe {
+                std::ptr::copy(
+                    old_field_arr_ptr.as_ptr(),
+                    new_field_arr_ptr.as_ptr(),
+                    field_metadata.size * self.length,
+                );
+            }
+        }
+
+        self.ptr = new_ptr;
+        self.layout = Some(new_layout);
+        self.length = new_length;
+        self.field_arr_byte_offsets = new_field_arr_byte_offsets;
+    }
+
+    fn do_first_alloc(&mut self)
     {
         let (layout, field_arr_byte_offsets) = Self::create_layout(1);
 
@@ -101,7 +140,10 @@ where
             handle_alloc_error(layout);
         };
 
-        (ptr, field_arr_byte_offsets, layout)
+        self.ptr = ptr;
+        self.length = 1;
+        self.field_arr_byte_offsets = field_arr_byte_offsets;
+        self.layout = Some(layout);
     }
 
     fn create_layout(length: usize) -> (Layout, Vec<usize>)
@@ -110,9 +152,12 @@ where
 
         let first_field_metadata = field_metadata_iter.next().unwrap();
 
-        let mut layout =
-            array_layout(first_field_metadata.size, first_field_metadata.alignment, 1)
-                .unwrap();
+        let mut layout = array_layout(
+            first_field_metadata.size,
+            first_field_metadata.alignment,
+            length,
+        )
+        .unwrap();
 
         let mut field_arr_byte_offsets = Vec::with_capacity(ItemT::FIELD_CNT);
 
@@ -197,7 +242,9 @@ where
 /// correctly represents fields of the implementor type.
 pub unsafe trait Item
 {
-    type FieldMetadataIter<'a>: Iterator<Item = &'a ItemFieldMetadata>;
+    type FieldMetadataIter<'a>: Iterator<Item = &'a ItemFieldMetadata>
+        + DoubleEndedIterator
+        + ExactSizeIterator;
 
     const FIELD_CNT: usize;
 
@@ -322,21 +369,6 @@ mod tests
         }
     }
 
-    struct FooFieldMetadataIter<'a>
-    {
-        iter: std::slice::Iter<'a, ItemFieldMetadata>,
-    }
-
-    impl<'a> Iterator for FooFieldMetadataIter<'a>
-    {
-        type Item = &'a ItemFieldMetadata;
-
-        fn next(&mut self) -> Option<Self::Item>
-        {
-            self.iter.next()
-        }
-    }
-
     static FOO_FIELD_METADATA: [ItemFieldMetadata; 2] = [
         ItemFieldMetadata {
             offset: offset_of!(Foo, num_a),
@@ -352,13 +384,13 @@ mod tests
 
     unsafe impl Item for Foo
     {
-        type FieldMetadataIter<'a> = FooFieldMetadataIter<'a>;
+        type FieldMetadataIter<'a> = std::slice::Iter<'a, ItemFieldMetadata>;
 
         const FIELD_CNT: usize = 2;
 
         fn iter_field_metadata() -> Self::FieldMetadataIter<'static>
         {
-            FooFieldMetadataIter { iter: FOO_FIELD_METADATA.iter() }
+            FOO_FIELD_METADATA.iter()
         }
 
         unsafe fn drop_field_inplace(field_index: usize, field_ptr: *mut u8)
@@ -378,7 +410,9 @@ mod tests
 
         multi_vec.push(Foo { num_a: 123, num_b: 654 });
 
-        let item = multi_vec.get::<FooFieldNumB>(0);
+        multi_vec.push(Foo { num_a: 12338, num_b: 191 });
+
+        let item = multi_vec.get::<FooFieldNumA>(1);
 
         println!("yay: {}", *item);
     }
-- 
cgit v1.2.3-18-g5258