1extern crate alloc;
59use alloc::vec;
60use alloc::vec::Vec;
61
62use grafos_std::error::{FabricError, Result};
63use grafos_std::mem::{MemBuilder, MemLease};
64
65use serde::{de::DeserializeOwned, Serialize};
66
67const HEADER_SIZE: u64 = 24; pub struct FabricVec<T> {
103 lease: MemLease,
104 len: u64,
105 capacity: u64,
106 stride: u64,
107 overflow: Vec<OverflowRegion>,
108 _marker: core::marker::PhantomData<T>,
109}
110
111struct OverflowRegion {
113 lease: MemLease,
114 capacity: u64,
115}
116
117impl<T: Serialize + DeserializeOwned> FabricVec<T> {
118 pub fn new(lease: MemLease, stride: usize) -> Result<Self> {
131 let arena = lease.mem().arena_size()?;
132 if arena < HEADER_SIZE {
133 return Err(FabricError::CapacityExceeded);
134 }
135 let stride = stride as u64;
136 let capacity = (arena - HEADER_SIZE) / stride;
137 let v = FabricVec {
138 lease,
139 len: 0,
140 capacity,
141 stride,
142 overflow: Vec::new(),
143 _marker: core::marker::PhantomData,
144 };
145 v.write_header()?;
146 Ok(v)
147 }
148
149 pub fn with_capacity(cap: usize, stride: usize) -> Result<Self> {
160 let needed = HEADER_SIZE + (cap as u64) * (stride as u64);
161 let lease = MemBuilder::new().min_bytes(needed).acquire()?;
162 Self::new(lease, stride)
163 }
164
165 pub fn push(&mut self, item: &T) -> Result<()> {
171 if self.len >= self.capacity {
172 self.grow()?;
173 }
174 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
175 if bytes.len() as u64 > self.stride {
176 return Err(FabricError::CapacityExceeded);
177 }
178 let (mem, offset) = self.resolve_slot(self.len);
179 let mut slot = vec![0u8; self.stride as usize];
180 let len_bytes = (bytes.len() as u32).to_le_bytes();
181 slot[..4].copy_from_slice(&len_bytes);
182 slot[4..4 + bytes.len()].copy_from_slice(&bytes);
183 mem.write(offset, &slot)?;
184 self.len += 1;
185 self.write_header()?;
186 Ok(())
187 }
188
189 pub fn grow(&mut self) -> Result<()> {
200 let primary_cap = (self.lease.mem().arena_size()? - HEADER_SIZE) / self.stride;
201 let needed = HEADER_SIZE + primary_cap * self.stride;
202 let new_lease = MemBuilder::new().min_bytes(needed).acquire()?;
203 let arena = new_lease.mem().arena_size()?;
204 let new_cap = (arena - HEADER_SIZE) / self.stride;
205 self.capacity += new_cap;
206 self.overflow.push(OverflowRegion {
207 lease: new_lease,
208 capacity: new_cap,
209 });
210 self.write_header()?;
211 Ok(())
212 }
213
214 pub fn pop(&mut self) -> Result<Option<T>> {
216 if self.len == 0 {
217 return Ok(None);
218 }
219 let item = self.get(self.len as usize - 1)?;
220 self.len -= 1;
221 self.write_header()?;
222 Ok(Some(item))
223 }
224
225 pub fn get(&self, index: usize) -> Result<T> {
231 if index as u64 >= self.len {
232 return Err(FabricError::CapacityExceeded);
233 }
234 let (mem, offset) = self.resolve_slot(index as u64);
235 let raw = mem.read(offset, self.stride as u32)?;
236 let ser_len = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]) as usize;
237 postcard::from_bytes(&raw[4..4 + ser_len]).map_err(|_| FabricError::IoError(-1))
238 }
239
240 pub fn set(&mut self, index: usize, item: &T) -> Result<()> {
246 if index as u64 >= self.len {
247 return Err(FabricError::CapacityExceeded);
248 }
249 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
250 if bytes.len() as u64 > self.stride {
251 return Err(FabricError::CapacityExceeded);
252 }
253 let (mem, offset) = self.resolve_slot(index as u64);
254 let mut slot = vec![0u8; self.stride as usize];
255 let len_bytes = (bytes.len() as u32).to_le_bytes();
256 slot[..4].copy_from_slice(&len_bytes);
257 slot[4..4 + bytes.len()].copy_from_slice(&bytes);
258 mem.write(offset, &slot)?;
259 Ok(())
260 }
261
262 pub fn len(&self) -> usize {
264 self.len as usize
265 }
266
267 pub fn is_empty(&self) -> bool {
269 self.len == 0
270 }
271
272 pub fn capacity(&self) -> usize {
274 self.capacity as usize
275 }
276
277 pub fn clear(&mut self) -> Result<()> {
279 self.len = 0;
280 self.write_header()
281 }
282
283 pub fn iter(&self) -> FabricVecIter<'_, T> {
285 FabricVecIter {
286 vec: self,
287 index: 0,
288 }
289 }
290
291 pub fn lease_id(&self) -> u128 {
294 self.lease.lease_id()
295 }
296
297 pub fn expires_at_unix_secs(&self) -> u64 {
300 self.lease.expires_at_unix_secs()
301 }
302
303 fn resolve_slot(&self, index: u64) -> (&grafos_std::mem::FabricMem, u64) {
306 let primary_cap = self.primary_capacity();
307 if index < primary_cap {
308 return (self.lease.mem(), HEADER_SIZE + index * self.stride);
309 }
310 let mut remaining = index - primary_cap;
311 for region in &self.overflow {
312 if remaining < region.capacity {
313 let offset = HEADER_SIZE + remaining * self.stride;
314 return (region.lease.mem(), offset);
315 }
316 remaining -= region.capacity;
317 }
318 (self.lease.mem(), 0)
322 }
323
324 fn primary_capacity(&self) -> u64 {
326 let arena = self.lease.mem().arena_size().unwrap_or(HEADER_SIZE);
327 (arena - HEADER_SIZE) / self.stride
328 }
329
330 fn write_header(&self) -> Result<()> {
331 let mut hdr = [0u8; HEADER_SIZE as usize];
332 hdr[0..8].copy_from_slice(&self.len.to_le_bytes());
333 hdr[8..16].copy_from_slice(&self.capacity.to_le_bytes());
334 hdr[16..24].copy_from_slice(&self.stride.to_le_bytes());
335 self.lease.mem().write(0, &hdr)
336 }
337}
338
339pub struct FabricVecIter<'a, T> {
347 vec: &'a FabricVec<T>,
348 index: usize,
349}
350
351impl<'a, T: Serialize + DeserializeOwned> Iterator for FabricVecIter<'a, T> {
352 type Item = Result<T>;
353
354 fn next(&mut self) -> Option<Self::Item> {
355 if self.index >= self.vec.len() {
356 return None;
357 }
358 let result = self.vec.get(self.index);
359 self.index += 1;
360 Some(result)
361 }
362
363 fn size_hint(&self) -> (usize, Option<usize>) {
364 let remaining = self.vec.len() - self.index;
365 (remaining, Some(remaining))
366 }
367}
368
369const VAR_HEADER_SIZE: u64 = 32; const INDEX_ENTRY_SIZE: u64 = 12; pub struct VarFabricVec<T> {
410 lease: MemLease,
411 len: u64,
412 index_cap: u64,
413 heap_start: u64,
414 heap_size: u64,
415 heap_used: u64,
416 _marker: core::marker::PhantomData<T>,
417}
418
419impl<T: Serialize + DeserializeOwned> VarFabricVec<T> {
420 pub fn new(lease: MemLease, max_elements: usize) -> Result<Self> {
431 let arena = lease.mem().arena_size()?;
432 let index_cap = max_elements as u64;
433 let heap_start = VAR_HEADER_SIZE + index_cap * INDEX_ENTRY_SIZE;
434 if arena <= heap_start {
435 return Err(FabricError::CapacityExceeded);
436 }
437 let heap_size = arena - heap_start;
438 let v = VarFabricVec {
439 lease,
440 len: 0,
441 index_cap,
442 heap_start,
443 heap_size,
444 heap_used: 0,
445 _marker: core::marker::PhantomData,
446 };
447 v.write_header()?;
448 Ok(v)
449 }
450
451 pub fn with_capacity(max_elements: usize, avg_element_bytes: usize) -> Result<Self> {
457 let needed = VAR_HEADER_SIZE
458 + (max_elements as u64) * INDEX_ENTRY_SIZE
459 + (max_elements as u64) * (avg_element_bytes as u64);
460 let lease = MemBuilder::new().min_bytes(needed).acquire()?;
461 Self::new(lease, max_elements)
462 }
463
464 pub fn push(&mut self, item: &T) -> Result<()> {
473 if self.len >= self.index_cap {
474 return Err(FabricError::CapacityExceeded);
475 }
476 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
477 if self.heap_used + bytes.len() as u64 > self.heap_size {
478 return Err(FabricError::CapacityExceeded);
479 }
480 let data_offset = self.heap_start + self.heap_used;
482 self.lease.mem().write(data_offset, &bytes)?;
483 let idx_offset = VAR_HEADER_SIZE + self.len * INDEX_ENTRY_SIZE;
485 let mut entry = [0u8; INDEX_ENTRY_SIZE as usize];
486 entry[0..8].copy_from_slice(&self.heap_used.to_le_bytes());
487 entry[8..12].copy_from_slice(&(bytes.len() as u32).to_le_bytes());
488 self.lease.mem().write(idx_offset, &entry)?;
489
490 self.heap_used += bytes.len() as u64;
491 self.len += 1;
492 self.write_header()?;
493 Ok(())
494 }
495
496 pub fn pop(&mut self) -> Result<Option<T>> {
501 if self.len == 0 {
502 return Ok(None);
503 }
504 let item = self.get(self.len as usize - 1)?;
505 let idx_offset = VAR_HEADER_SIZE + (self.len - 1) * INDEX_ENTRY_SIZE;
507 let entry = self.lease.mem().read(idx_offset, INDEX_ENTRY_SIZE as u32)?;
508 let heap_offset = u64::from_le_bytes([
509 entry[0], entry[1], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7],
510 ]);
511 let data_len = u32::from_le_bytes([entry[8], entry[9], entry[10], entry[11]]) as u64;
512 if heap_offset + data_len == self.heap_used {
514 self.heap_used = heap_offset;
515 }
516 self.len -= 1;
517 self.write_header()?;
518 Ok(Some(item))
519 }
520
521 pub fn get(&self, index: usize) -> Result<T> {
526 if index as u64 >= self.len {
527 return Err(FabricError::CapacityExceeded);
528 }
529 let idx_offset = VAR_HEADER_SIZE + (index as u64) * INDEX_ENTRY_SIZE;
530 let entry = self.lease.mem().read(idx_offset, INDEX_ENTRY_SIZE as u32)?;
531 let heap_offset = u64::from_le_bytes([
532 entry[0], entry[1], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7],
533 ]);
534 let data_len = u32::from_le_bytes([entry[8], entry[9], entry[10], entry[11]]);
535 let data = self
536 .lease
537 .mem()
538 .read(self.heap_start + heap_offset, data_len)?;
539 postcard::from_bytes(&data).map_err(|_| FabricError::IoError(-1))
540 }
541
542 pub fn len(&self) -> usize {
544 self.len as usize
545 }
546
547 pub fn is_empty(&self) -> bool {
549 self.len == 0
550 }
551
552 pub fn index_capacity(&self) -> usize {
554 self.index_cap as usize
555 }
556
557 pub fn heap_size(&self) -> u64 {
559 self.heap_size
560 }
561
562 pub fn heap_used(&self) -> u64 {
564 self.heap_used
565 }
566
567 pub fn clear(&mut self) -> Result<()> {
569 self.len = 0;
570 self.heap_used = 0;
571 self.write_header()
572 }
573
574 pub fn lease_id(&self) -> u128 {
577 self.lease.lease_id()
578 }
579
580 pub fn expires_at_unix_secs(&self) -> u64 {
583 self.lease.expires_at_unix_secs()
584 }
585
586 pub fn iter(&self) -> VarFabricVecIter<'_, T> {
588 VarFabricVecIter {
589 vec: self,
590 index: 0,
591 }
592 }
593
594 fn write_header(&self) -> Result<()> {
595 let mut hdr = [0u8; VAR_HEADER_SIZE as usize];
596 hdr[0..8].copy_from_slice(&self.len.to_le_bytes());
597 hdr[8..16].copy_from_slice(&self.index_cap.to_le_bytes());
598 hdr[16..24].copy_from_slice(&self.heap_size.to_le_bytes());
599 hdr[24..32].copy_from_slice(&self.heap_used.to_le_bytes());
600 self.lease.mem().write(0, &hdr)
601 }
602}
603
604pub struct VarFabricVecIter<'a, T> {
606 vec: &'a VarFabricVec<T>,
607 index: usize,
608}
609
610impl<'a, T: Serialize + DeserializeOwned> Iterator for VarFabricVecIter<'a, T> {
611 type Item = Result<T>;
612
613 fn next(&mut self) -> Option<Self::Item> {
614 if self.index >= self.vec.len() {
615 return None;
616 }
617 let result = self.vec.get(self.index);
618 self.index += 1;
619 Some(result)
620 }
621
622 fn size_hint(&self) -> (usize, Option<usize>) {
623 let remaining = self.vec.len() - self.index;
624 (remaining, Some(remaining))
625 }
626}
627
628#[cfg(test)]
629mod tests {
630 use super::*;
631 use grafos_std::host;
632 use serde::{Deserialize, Serialize};
633
634 fn setup(arena_size: u64) -> MemLease {
635 host::reset_mock();
636 host::mock_set_fbmu_arena_size(arena_size);
637 MemBuilder::new().acquire().expect("acquire")
638 }
639
640 #[test]
641 fn push_pop_roundtrip() {
642 let lease = setup(4096);
643 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
644 assert!(v.is_empty());
645
646 v.push(&10).expect("push 10");
647 v.push(&20).expect("push 20");
648 v.push(&30).expect("push 30");
649 assert_eq!(v.len(), 3);
650
651 assert_eq!(v.pop().expect("pop"), Some(30));
652 assert_eq!(v.pop().expect("pop"), Some(20));
653 assert_eq!(v.pop().expect("pop"), Some(10));
654 assert_eq!(v.pop().expect("pop"), None);
655 assert!(v.is_empty());
656 }
657
658 #[test]
659 fn get_set() {
660 let lease = setup(4096);
661 let mut v: FabricVec<u64> = FabricVec::new(lease, 16).expect("new");
662
663 v.push(&100).expect("push");
664 v.push(&200).expect("push");
665 v.push(&300).expect("push");
666
667 assert_eq!(v.get(0).expect("get"), 100);
668 assert_eq!(v.get(1).expect("get"), 200);
669 assert_eq!(v.get(2).expect("get"), 300);
670
671 v.set(1, &999).expect("set");
672 assert_eq!(v.get(1).expect("get"), 999);
673 }
674
675 #[test]
676 fn get_out_of_bounds() {
677 let lease = setup(4096);
678 let v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
679 assert_eq!(v.get(0).unwrap_err(), FabricError::CapacityExceeded);
680 }
681
682 #[test]
683 fn iter_elements() {
684 let lease = setup(4096);
685 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
686 for i in 0..5u32 {
687 v.push(&i).expect("push");
688 }
689 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
690 assert_eq!(collected, alloc::vec![0, 1, 2, 3, 4]);
691 }
692
693 #[test]
694 fn vec_lease_accessors() {
695 let lease = setup(4096);
696 let v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
697 assert_ne!(v.lease_id(), 0);
698 assert!(v.expires_at_unix_secs() > 0);
699 }
700
701 #[test]
702 fn clear_resets_len() {
703 let lease = setup(4096);
704 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
705 v.push(&1).expect("push");
706 v.push(&2).expect("push");
707 assert_eq!(v.len(), 2);
708 v.clear().expect("clear");
709 assert_eq!(v.len(), 0);
710 assert!(v.is_empty());
711 }
712
713 #[test]
714 fn capacity_exceeded_when_grow_fails() {
715 let lease = setup(56);
717 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
718 assert_eq!(v.capacity(), 2);
719
720 v.push(&1).expect("push 1");
721 v.push(&2).expect("push 2");
722 host::mock_set_fbmu_arena_size(0);
724 assert_eq!(v.push(&3).unwrap_err(), FabricError::CapacityExceeded);
725 }
726
727 #[test]
728 fn with_capacity_creates_appropriately_sized_vec() {
729 host::reset_mock();
730 host::mock_set_fbmu_arena_size(65536);
731
732 let v: FabricVec<u64> = FabricVec::with_capacity(100, 16).expect("with_capacity");
733 assert!(v.capacity() >= 100);
734 }
735
736 #[derive(Debug, PartialEq, Serialize, Deserialize)]
737 struct TestStruct {
738 name: alloc::string::String,
739 value: u64,
740 }
741
742 #[test]
743 fn variable_size_elements() {
744 let lease = setup(8192);
745 let mut v: FabricVec<TestStruct> = FabricVec::new(lease, 64).expect("new");
746
747 let a = TestStruct {
748 name: alloc::string::String::from("alpha"),
749 value: 42,
750 };
751 let b = TestStruct {
752 name: alloc::string::String::from("beta"),
753 value: 99,
754 };
755
756 v.push(&a).expect("push a");
757 v.push(&b).expect("push b");
758
759 assert_eq!(v.get(0).expect("get 0"), a);
760 assert_eq!(v.get(1).expect("get 1"), b);
761 }
762
763 #[test]
764 fn variable_size_elements_different_serialized_lengths() {
765 let lease = setup(8192);
768 let mut v: FabricVec<TestStruct> = FabricVec::new(lease, 128).expect("new");
769
770 let short = TestStruct {
771 name: alloc::string::String::from("x"),
772 value: 1,
773 };
774 let long = TestStruct {
775 name: alloc::string::String::from("a]relatively_long_name_for_testing_purposes"),
776 value: u64::MAX,
777 };
778 let empty = TestStruct {
779 name: alloc::string::String::new(),
780 value: 0,
781 };
782
783 v.push(&short).expect("push short");
784 v.push(&long).expect("push long");
785 v.push(&empty).expect("push empty");
786
787 assert_eq!(v.get(0).expect("get 0"), short);
788 assert_eq!(v.get(1).expect("get 1"), long);
789 assert_eq!(v.get(2).expect("get 2"), empty);
790
791 v.set(0, &long).expect("set 0 to long");
793 assert_eq!(v.get(0).expect("get 0 after set"), long);
794 }
795
796 #[test]
797 fn variable_size_element_exceeds_stride_returns_error() {
798 let lease = setup(4096);
802 let mut v: FabricVec<alloc::string::String> = FabricVec::new(lease, 16).expect("new");
803
804 let big = alloc::string::String::from("12345678901234567890");
806 assert_eq!(v.push(&big).unwrap_err(), FabricError::CapacityExceeded);
807 assert!(v.is_empty());
808 }
809
810 #[test]
811 fn capacity_boundary_fill_then_pop_then_refill() {
812 let lease = setup(88);
815 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
816 assert_eq!(v.capacity(), 4);
817
818 for i in 0..4u32 {
820 v.push(&(i * 10)).expect("push");
821 }
822 assert_eq!(v.len(), 4);
823 host::mock_set_fbmu_arena_size(0);
825 assert_eq!(v.push(&99).unwrap_err(), FabricError::CapacityExceeded);
826 host::mock_set_fbmu_arena_size(88);
828
829 for i in (0..4u32).rev() {
831 assert_eq!(v.pop().expect("pop"), Some(i * 10));
832 }
833 assert!(v.is_empty());
834
835 for i in 100..104u32 {
837 v.push(&i).expect("re-push");
838 }
839 assert_eq!(v.len(), 4);
840 for (idx, expected) in (100..104u32).enumerate() {
841 assert_eq!(v.get(idx).expect("get"), expected);
842 }
843 }
844
845 #[test]
846 fn arena_too_small_for_header() {
847 let lease = setup(16);
849 let result: core::result::Result<FabricVec<u32>, _> = FabricVec::new(lease, 16);
850 match result {
851 Err(FabricError::CapacityExceeded) => {}
852 other => panic!("expected CapacityExceeded, got {:?}", other.err()),
853 }
854 }
855
856 #[test]
857 fn set_out_of_bounds() {
858 let lease = setup(4096);
859 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
860 v.push(&42).expect("push");
861 assert_eq!(v.set(1, &99).unwrap_err(), FabricError::CapacityExceeded);
863 assert_eq!(v.get(0).expect("get"), 42);
865 }
866
867 #[test]
868 fn iter_size_hint() {
869 let lease = setup(4096);
870 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
871 for i in 0..5u32 {
872 v.push(&i).expect("push");
873 }
874 let mut iter = v.iter();
875 assert_eq!(iter.size_hint(), (5, Some(5)));
876 iter.next();
877 assert_eq!(iter.size_hint(), (4, Some(4)));
878 }
879
880 #[test]
883 fn grow_chains_new_lease() {
884 host::reset_mock();
886 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
888 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
889 assert_eq!(v.capacity(), 2);
890
891 v.push(&10).expect("push 10");
892 v.push(&20).expect("push 20");
893
894 host::mock_set_fbmu_arena_size(56);
896 v.push(&30).expect("push 30 (triggers grow)");
897 assert!(v.capacity() >= 3);
898 assert_eq!(v.len(), 3);
899
900 assert_eq!(v.get(0).expect("get 0"), 10);
901 assert_eq!(v.get(1).expect("get 1"), 20);
902 assert_eq!(v.get(2).expect("get 2"), 30);
903 }
904
905 #[test]
906 fn grow_multiple_overflow_regions() {
907 host::reset_mock();
908 host::mock_set_fbmu_arena_size(56);
910 let lease = MemBuilder::new().acquire().expect("acquire");
911 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
912 assert_eq!(v.capacity(), 2);
913
914 for i in 0..6u32 {
916 v.push(&(i * 10)).expect("push");
917 }
918 assert_eq!(v.len(), 6);
919 assert!(v.capacity() >= 6);
920
921 for i in 0..6u32 {
923 assert_eq!(v.get(i as usize).expect("get"), i * 10);
924 }
925
926 for i in (0..6u32).rev() {
928 assert_eq!(v.pop().expect("pop"), Some(i * 10));
929 }
930 assert!(v.is_empty());
931 }
932
933 #[test]
934 fn grow_iter_spans_regions() {
935 host::reset_mock();
936 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
938 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
939
940 for i in 0..5u32 {
941 v.push(&i).expect("push");
942 }
943 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
944 assert_eq!(collected, alloc::vec![0, 1, 2, 3, 4]);
945 }
946
947 #[test]
948 fn grow_set_in_overflow_region() {
949 host::reset_mock();
950 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
952 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
953
954 v.push(&1).expect("push");
955 v.push(&2).expect("push");
956 v.push(&3).expect("push"); v.set(2, &99).expect("set in overflow");
959 assert_eq!(v.get(2).expect("get"), 99);
960 }
961
962 #[test]
965 fn fabric_vec_string_elements() {
966 let lease = setup(8192);
967 let mut v: FabricVec<alloc::string::String> = FabricVec::new(lease, 64).expect("new");
968
969 let strings = alloc::vec![
970 alloc::string::String::from("hello"),
971 alloc::string::String::from("world"),
972 alloc::string::String::from(""),
973 alloc::string::String::from("a longer string with more characters"),
974 ];
975 for s in &strings {
976 v.push(s).expect("push");
977 }
978 for (i, s) in strings.iter().enumerate() {
979 assert_eq!(&v.get(i).expect("get"), s);
980 }
981 }
982
983 #[test]
984 fn fabric_vec_vec_u8_elements() {
985 let lease = setup(8192);
986 let mut v: FabricVec<alloc::vec::Vec<u8>> = FabricVec::new(lease, 64).expect("new");
987
988 let items: alloc::vec::Vec<alloc::vec::Vec<u8>> =
989 alloc::vec![alloc::vec![1, 2, 3], alloc::vec![], alloc::vec![255; 50],];
990 for item in &items {
991 v.push(item).expect("push");
992 }
993 for (i, item) in items.iter().enumerate() {
994 assert_eq!(&v.get(i).expect("get"), item);
995 }
996 }
997
998 #[test]
1001 fn var_vec_push_pop_roundtrip() {
1002 let lease = setup(8192);
1003 let mut v: VarFabricVec<alloc::string::String> =
1004 VarFabricVec::new(lease, 100).expect("new");
1005
1006 v.push(&alloc::string::String::from("short")).expect("push");
1007 v.push(&alloc::string::String::from(
1008 "a much longer string that takes more heap space",
1009 ))
1010 .expect("push");
1011 v.push(&alloc::string::String::from("")).expect("push");
1012 assert_eq!(v.len(), 3);
1013
1014 assert_eq!(
1015 v.get(0).expect("get 0"),
1016 alloc::string::String::from("short")
1017 );
1018 assert_eq!(
1019 v.get(1).expect("get 1"),
1020 alloc::string::String::from("a much longer string that takes more heap space")
1021 );
1022 assert_eq!(v.get(2).expect("get 2"), alloc::string::String::from(""));
1023
1024 assert_eq!(v.pop().expect("pop"), Some(alloc::string::String::from("")));
1025 assert_eq!(v.len(), 2);
1026 }
1027
1028 #[test]
1029 fn var_vec_mixed_sizes_efficient() {
1030 let lease = setup(8192);
1031 let mut v: VarFabricVec<alloc::vec::Vec<u8>> = VarFabricVec::new(lease, 100).expect("new");
1032
1033 v.push(&alloc::vec![42u8]).expect("push tiny");
1035 v.push(&alloc::vec![0u8; 100]).expect("push medium");
1036 v.push(&alloc::vec![255u8; 500]).expect("push large");
1037
1038 assert_eq!(v.len(), 3);
1039 assert_eq!(v.get(0).expect("get 0"), alloc::vec![42u8]);
1040 assert_eq!(v.get(1).expect("get 1"), alloc::vec![0u8; 100]);
1041 assert_eq!(v.get(2).expect("get 2"), alloc::vec![255u8; 500]);
1042
1043 assert!(v.heap_used() < 1000);
1046 }
1047
1048 #[test]
1049 fn var_vec_with_capacity() {
1050 host::reset_mock();
1051 host::mock_set_fbmu_arena_size(65536);
1052 let v: VarFabricVec<alloc::string::String> =
1053 VarFabricVec::with_capacity(50, 32).expect("with_capacity");
1054 assert_eq!(v.index_capacity(), 50);
1055 assert!(v.heap_size() > 0);
1056 }
1057
1058 #[test]
1059 fn var_vec_clear() {
1060 let lease = setup(8192);
1061 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 100).expect("new");
1062 v.push(&1).expect("push");
1063 v.push(&2).expect("push");
1064 v.clear().expect("clear");
1065 assert!(v.is_empty());
1066 assert_eq!(v.heap_used(), 0);
1067 }
1068
1069 #[test]
1070 fn var_vec_iter() {
1071 let lease = setup(8192);
1072 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 100).expect("new");
1073 for i in 0..5u32 {
1074 v.push(&(i * 10)).expect("push");
1075 }
1076 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
1077 assert_eq!(collected, alloc::vec![0, 10, 20, 30, 40]);
1078 }
1079
1080 #[test]
1081 fn var_vec_heap_full_returns_error() {
1082 let lease = setup(256);
1086 let mut v: VarFabricVec<alloc::vec::Vec<u8>> = VarFabricVec::new(lease, 10).expect("new");
1087 v.push(&alloc::vec![0u8; 60]).expect("push 1");
1089 let result = v.push(&alloc::vec![0u8; 60]);
1091 assert_eq!(result.unwrap_err(), FabricError::CapacityExceeded);
1092 assert_eq!(v.len(), 1);
1093 }
1094
1095 #[test]
1096 fn var_vec_index_full_returns_error() {
1097 let lease = setup(4096);
1100 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 2).expect("new");
1101 v.push(&1).expect("push 1");
1102 v.push(&2).expect("push 2");
1103 assert_eq!(v.push(&3).unwrap_err(), FabricError::CapacityExceeded);
1104 }
1105
1106 #[test]
1107 fn var_vec_pop_reclaims_heap() {
1108 let lease = setup(8192);
1109 let mut v: VarFabricVec<alloc::string::String> =
1110 VarFabricVec::new(lease, 100).expect("new");
1111 v.push(&alloc::string::String::from("first")).expect("push");
1112 let after_first = v.heap_used();
1113 v.push(&alloc::string::String::from("second"))
1114 .expect("push");
1115 let after_second = v.heap_used();
1116 assert!(after_second > after_first);
1117
1118 v.pop().expect("pop");
1120 assert_eq!(v.heap_used(), after_first);
1121 }
1122}