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> {
99 lease: MemLease,
100 len: u64,
101 capacity: u64,
102 stride: u64,
103 overflow: Vec<OverflowRegion>,
104 _marker: core::marker::PhantomData<T>,
105}
106
107struct OverflowRegion {
109 lease: MemLease,
110 capacity: u64,
111}
112
113impl<T: Serialize + DeserializeOwned> FabricVec<T> {
114 pub fn new(lease: MemLease, stride: usize) -> Result<Self> {
127 let arena = lease.mem().arena_size()?;
128 if arena < HEADER_SIZE {
129 return Err(FabricError::CapacityExceeded);
130 }
131 let stride = stride as u64;
132 let capacity = (arena - HEADER_SIZE) / stride;
133 let v = FabricVec {
134 lease,
135 len: 0,
136 capacity,
137 stride,
138 overflow: Vec::new(),
139 _marker: core::marker::PhantomData,
140 };
141 v.write_header()?;
142 Ok(v)
143 }
144
145 pub fn with_capacity(cap: usize, stride: usize) -> Result<Self> {
156 let needed = HEADER_SIZE + (cap as u64) * (stride as u64);
157 let lease = MemBuilder::new().min_bytes(needed).acquire()?;
158 Self::new(lease, stride)
159 }
160
161 pub fn push(&mut self, item: &T) -> Result<()> {
167 if self.len >= self.capacity {
168 self.grow()?;
169 }
170 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
171 if bytes.len() as u64 > self.stride {
172 return Err(FabricError::CapacityExceeded);
173 }
174 let (mem, offset) = self.resolve_slot(self.len);
175 let mut slot = vec![0u8; self.stride as usize];
176 let len_bytes = (bytes.len() as u32).to_le_bytes();
177 slot[..4].copy_from_slice(&len_bytes);
178 slot[4..4 + bytes.len()].copy_from_slice(&bytes);
179 mem.write(offset, &slot)?;
180 self.len += 1;
181 self.write_header()?;
182 Ok(())
183 }
184
185 pub fn grow(&mut self) -> Result<()> {
196 let primary_cap = (self.lease.mem().arena_size()? - HEADER_SIZE) / self.stride;
197 let needed = HEADER_SIZE + primary_cap * self.stride;
198 let new_lease = MemBuilder::new().min_bytes(needed).acquire()?;
199 let arena = new_lease.mem().arena_size()?;
200 let new_cap = (arena - HEADER_SIZE) / self.stride;
201 self.capacity += new_cap;
202 self.overflow.push(OverflowRegion {
203 lease: new_lease,
204 capacity: new_cap,
205 });
206 self.write_header()?;
207 Ok(())
208 }
209
210 pub fn pop(&mut self) -> Result<Option<T>> {
212 if self.len == 0 {
213 return Ok(None);
214 }
215 let item = self.get(self.len as usize - 1)?;
216 self.len -= 1;
217 self.write_header()?;
218 Ok(Some(item))
219 }
220
221 pub fn get(&self, index: usize) -> Result<T> {
227 if index as u64 >= self.len {
228 return Err(FabricError::CapacityExceeded);
229 }
230 let (mem, offset) = self.resolve_slot(index as u64);
231 let raw = mem.read(offset, self.stride as u32)?;
232 let ser_len = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]) as usize;
233 postcard::from_bytes(&raw[4..4 + ser_len]).map_err(|_| FabricError::IoError(-1))
234 }
235
236 pub fn set(&mut self, index: usize, item: &T) -> Result<()> {
242 if index as u64 >= self.len {
243 return Err(FabricError::CapacityExceeded);
244 }
245 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
246 if bytes.len() as u64 > self.stride {
247 return Err(FabricError::CapacityExceeded);
248 }
249 let (mem, offset) = self.resolve_slot(index as u64);
250 let mut slot = vec![0u8; self.stride as usize];
251 let len_bytes = (bytes.len() as u32).to_le_bytes();
252 slot[..4].copy_from_slice(&len_bytes);
253 slot[4..4 + bytes.len()].copy_from_slice(&bytes);
254 mem.write(offset, &slot)?;
255 Ok(())
256 }
257
258 pub fn len(&self) -> usize {
260 self.len as usize
261 }
262
263 pub fn is_empty(&self) -> bool {
265 self.len == 0
266 }
267
268 pub fn capacity(&self) -> usize {
270 self.capacity as usize
271 }
272
273 pub fn clear(&mut self) -> Result<()> {
275 self.len = 0;
276 self.write_header()
277 }
278
279 pub fn iter(&self) -> FabricVecIter<'_, T> {
281 FabricVecIter {
282 vec: self,
283 index: 0,
284 }
285 }
286
287 pub fn lease_id(&self) -> u128 {
290 self.lease.lease_id()
291 }
292
293 pub fn expires_at_unix_secs(&self) -> u64 {
296 self.lease.expires_at_unix_secs()
297 }
298
299 fn resolve_slot(&self, index: u64) -> (&grafos_std::mem::FabricMem, u64) {
302 let primary_cap = self.primary_capacity();
303 if index < primary_cap {
304 return (self.lease.mem(), HEADER_SIZE + index * self.stride);
305 }
306 let mut remaining = index - primary_cap;
307 for region in &self.overflow {
308 if remaining < region.capacity {
309 let offset = HEADER_SIZE + remaining * self.stride;
310 return (region.lease.mem(), offset);
311 }
312 remaining -= region.capacity;
313 }
314 (self.lease.mem(), 0)
318 }
319
320 fn primary_capacity(&self) -> u64 {
322 let arena = self.lease.mem().arena_size().unwrap_or(HEADER_SIZE);
323 (arena - HEADER_SIZE) / self.stride
324 }
325
326 fn write_header(&self) -> Result<()> {
327 let mut hdr = [0u8; HEADER_SIZE as usize];
328 hdr[0..8].copy_from_slice(&self.len.to_le_bytes());
329 hdr[8..16].copy_from_slice(&self.capacity.to_le_bytes());
330 hdr[16..24].copy_from_slice(&self.stride.to_le_bytes());
331 self.lease.mem().write(0, &hdr)
332 }
333}
334
335pub struct FabricVecIter<'a, T> {
343 vec: &'a FabricVec<T>,
344 index: usize,
345}
346
347impl<'a, T: Serialize + DeserializeOwned> Iterator for FabricVecIter<'a, T> {
348 type Item = Result<T>;
349
350 fn next(&mut self) -> Option<Self::Item> {
351 if self.index >= self.vec.len() {
352 return None;
353 }
354 let result = self.vec.get(self.index);
355 self.index += 1;
356 Some(result)
357 }
358
359 fn size_hint(&self) -> (usize, Option<usize>) {
360 let remaining = self.vec.len() - self.index;
361 (remaining, Some(remaining))
362 }
363}
364
365const VAR_HEADER_SIZE: u64 = 32; const INDEX_ENTRY_SIZE: u64 = 12; pub struct VarFabricVec<T> {
406 lease: MemLease,
407 len: u64,
408 index_cap: u64,
409 heap_start: u64,
410 heap_size: u64,
411 heap_used: u64,
412 _marker: core::marker::PhantomData<T>,
413}
414
415impl<T: Serialize + DeserializeOwned> VarFabricVec<T> {
416 pub fn new(lease: MemLease, max_elements: usize) -> Result<Self> {
427 let arena = lease.mem().arena_size()?;
428 let index_cap = max_elements as u64;
429 let heap_start = VAR_HEADER_SIZE + index_cap * INDEX_ENTRY_SIZE;
430 if arena <= heap_start {
431 return Err(FabricError::CapacityExceeded);
432 }
433 let heap_size = arena - heap_start;
434 let v = VarFabricVec {
435 lease,
436 len: 0,
437 index_cap,
438 heap_start,
439 heap_size,
440 heap_used: 0,
441 _marker: core::marker::PhantomData,
442 };
443 v.write_header()?;
444 Ok(v)
445 }
446
447 pub fn with_capacity(max_elements: usize, avg_element_bytes: usize) -> Result<Self> {
453 let needed = VAR_HEADER_SIZE
454 + (max_elements as u64) * INDEX_ENTRY_SIZE
455 + (max_elements as u64) * (avg_element_bytes as u64);
456 let lease = MemBuilder::new().min_bytes(needed).acquire()?;
457 Self::new(lease, max_elements)
458 }
459
460 pub fn push(&mut self, item: &T) -> Result<()> {
469 if self.len >= self.index_cap {
470 return Err(FabricError::CapacityExceeded);
471 }
472 let bytes = postcard::to_allocvec(item).map_err(|_| FabricError::IoError(-1))?;
473 if self.heap_used + bytes.len() as u64 > self.heap_size {
474 return Err(FabricError::CapacityExceeded);
475 }
476 let data_offset = self.heap_start + self.heap_used;
478 self.lease.mem().write(data_offset, &bytes)?;
479 let idx_offset = VAR_HEADER_SIZE + self.len * INDEX_ENTRY_SIZE;
481 let mut entry = [0u8; INDEX_ENTRY_SIZE as usize];
482 entry[0..8].copy_from_slice(&self.heap_used.to_le_bytes());
483 entry[8..12].copy_from_slice(&(bytes.len() as u32).to_le_bytes());
484 self.lease.mem().write(idx_offset, &entry)?;
485
486 self.heap_used += bytes.len() as u64;
487 self.len += 1;
488 self.write_header()?;
489 Ok(())
490 }
491
492 pub fn pop(&mut self) -> Result<Option<T>> {
497 if self.len == 0 {
498 return Ok(None);
499 }
500 let item = self.get(self.len as usize - 1)?;
501 let idx_offset = VAR_HEADER_SIZE + (self.len - 1) * INDEX_ENTRY_SIZE;
503 let entry = self.lease.mem().read(idx_offset, INDEX_ENTRY_SIZE as u32)?;
504 let heap_offset = u64::from_le_bytes([
505 entry[0], entry[1], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7],
506 ]);
507 let data_len = u32::from_le_bytes([entry[8], entry[9], entry[10], entry[11]]) as u64;
508 if heap_offset + data_len == self.heap_used {
510 self.heap_used = heap_offset;
511 }
512 self.len -= 1;
513 self.write_header()?;
514 Ok(Some(item))
515 }
516
517 pub fn get(&self, index: usize) -> Result<T> {
522 if index as u64 >= self.len {
523 return Err(FabricError::CapacityExceeded);
524 }
525 let idx_offset = VAR_HEADER_SIZE + (index as u64) * INDEX_ENTRY_SIZE;
526 let entry = self.lease.mem().read(idx_offset, INDEX_ENTRY_SIZE as u32)?;
527 let heap_offset = u64::from_le_bytes([
528 entry[0], entry[1], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7],
529 ]);
530 let data_len = u32::from_le_bytes([entry[8], entry[9], entry[10], entry[11]]);
531 let data = self
532 .lease
533 .mem()
534 .read(self.heap_start + heap_offset, data_len)?;
535 postcard::from_bytes(&data).map_err(|_| FabricError::IoError(-1))
536 }
537
538 pub fn len(&self) -> usize {
540 self.len as usize
541 }
542
543 pub fn is_empty(&self) -> bool {
545 self.len == 0
546 }
547
548 pub fn index_capacity(&self) -> usize {
550 self.index_cap as usize
551 }
552
553 pub fn heap_size(&self) -> u64 {
555 self.heap_size
556 }
557
558 pub fn heap_used(&self) -> u64 {
560 self.heap_used
561 }
562
563 pub fn clear(&mut self) -> Result<()> {
565 self.len = 0;
566 self.heap_used = 0;
567 self.write_header()
568 }
569
570 pub fn lease_id(&self) -> u128 {
573 self.lease.lease_id()
574 }
575
576 pub fn expires_at_unix_secs(&self) -> u64 {
579 self.lease.expires_at_unix_secs()
580 }
581
582 pub fn iter(&self) -> VarFabricVecIter<'_, T> {
584 VarFabricVecIter {
585 vec: self,
586 index: 0,
587 }
588 }
589
590 fn write_header(&self) -> Result<()> {
591 let mut hdr = [0u8; VAR_HEADER_SIZE as usize];
592 hdr[0..8].copy_from_slice(&self.len.to_le_bytes());
593 hdr[8..16].copy_from_slice(&self.index_cap.to_le_bytes());
594 hdr[16..24].copy_from_slice(&self.heap_size.to_le_bytes());
595 hdr[24..32].copy_from_slice(&self.heap_used.to_le_bytes());
596 self.lease.mem().write(0, &hdr)
597 }
598}
599
600pub struct VarFabricVecIter<'a, T> {
602 vec: &'a VarFabricVec<T>,
603 index: usize,
604}
605
606impl<'a, T: Serialize + DeserializeOwned> Iterator for VarFabricVecIter<'a, T> {
607 type Item = Result<T>;
608
609 fn next(&mut self) -> Option<Self::Item> {
610 if self.index >= self.vec.len() {
611 return None;
612 }
613 let result = self.vec.get(self.index);
614 self.index += 1;
615 Some(result)
616 }
617
618 fn size_hint(&self) -> (usize, Option<usize>) {
619 let remaining = self.vec.len() - self.index;
620 (remaining, Some(remaining))
621 }
622}
623
624#[cfg(test)]
625mod tests {
626 use super::*;
627 use grafos_std::host;
628 use serde::{Deserialize, Serialize};
629
630 fn setup(arena_size: u64) -> MemLease {
631 host::reset_mock();
632 host::mock_set_fbmu_arena_size(arena_size);
633 MemBuilder::new().acquire().expect("acquire")
634 }
635
636 #[test]
637 fn push_pop_roundtrip() {
638 let lease = setup(4096);
639 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
640 assert!(v.is_empty());
641
642 v.push(&10).expect("push 10");
643 v.push(&20).expect("push 20");
644 v.push(&30).expect("push 30");
645 assert_eq!(v.len(), 3);
646
647 assert_eq!(v.pop().expect("pop"), Some(30));
648 assert_eq!(v.pop().expect("pop"), Some(20));
649 assert_eq!(v.pop().expect("pop"), Some(10));
650 assert_eq!(v.pop().expect("pop"), None);
651 assert!(v.is_empty());
652 }
653
654 #[test]
655 fn get_set() {
656 let lease = setup(4096);
657 let mut v: FabricVec<u64> = FabricVec::new(lease, 16).expect("new");
658
659 v.push(&100).expect("push");
660 v.push(&200).expect("push");
661 v.push(&300).expect("push");
662
663 assert_eq!(v.get(0).expect("get"), 100);
664 assert_eq!(v.get(1).expect("get"), 200);
665 assert_eq!(v.get(2).expect("get"), 300);
666
667 v.set(1, &999).expect("set");
668 assert_eq!(v.get(1).expect("get"), 999);
669 }
670
671 #[test]
672 fn get_out_of_bounds() {
673 let lease = setup(4096);
674 let v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
675 assert_eq!(v.get(0).unwrap_err(), FabricError::CapacityExceeded);
676 }
677
678 #[test]
679 fn iter_elements() {
680 let lease = setup(4096);
681 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
682 for i in 0..5u32 {
683 v.push(&i).expect("push");
684 }
685 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
686 assert_eq!(collected, alloc::vec![0, 1, 2, 3, 4]);
687 }
688
689 #[test]
690 fn vec_lease_accessors() {
691 let lease = setup(4096);
692 let v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
693 assert_ne!(v.lease_id(), 0);
694 assert!(v.expires_at_unix_secs() > 0);
695 }
696
697 #[test]
698 fn clear_resets_len() {
699 let lease = setup(4096);
700 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
701 v.push(&1).expect("push");
702 v.push(&2).expect("push");
703 assert_eq!(v.len(), 2);
704 v.clear().expect("clear");
705 assert_eq!(v.len(), 0);
706 assert!(v.is_empty());
707 }
708
709 #[test]
710 fn capacity_exceeded_when_grow_fails() {
711 let lease = setup(56);
713 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
714 assert_eq!(v.capacity(), 2);
715
716 v.push(&1).expect("push 1");
717 v.push(&2).expect("push 2");
718 host::mock_set_fbmu_arena_size(0);
720 assert_eq!(v.push(&3).unwrap_err(), FabricError::CapacityExceeded);
721 }
722
723 #[test]
724 fn with_capacity_creates_appropriately_sized_vec() {
725 host::reset_mock();
726 host::mock_set_fbmu_arena_size(65536);
727
728 let v: FabricVec<u64> = FabricVec::with_capacity(100, 16).expect("with_capacity");
729 assert!(v.capacity() >= 100);
730 }
731
732 #[derive(Debug, PartialEq, Serialize, Deserialize)]
733 struct TestStruct {
734 name: alloc::string::String,
735 value: u64,
736 }
737
738 #[test]
739 fn variable_size_elements() {
740 let lease = setup(8192);
741 let mut v: FabricVec<TestStruct> = FabricVec::new(lease, 64).expect("new");
742
743 let a = TestStruct {
744 name: alloc::string::String::from("alpha"),
745 value: 42,
746 };
747 let b = TestStruct {
748 name: alloc::string::String::from("beta"),
749 value: 99,
750 };
751
752 v.push(&a).expect("push a");
753 v.push(&b).expect("push b");
754
755 assert_eq!(v.get(0).expect("get 0"), a);
756 assert_eq!(v.get(1).expect("get 1"), b);
757 }
758
759 #[test]
760 fn variable_size_elements_different_serialized_lengths() {
761 let lease = setup(8192);
764 let mut v: FabricVec<TestStruct> = FabricVec::new(lease, 128).expect("new");
765
766 let short = TestStruct {
767 name: alloc::string::String::from("x"),
768 value: 1,
769 };
770 let long = TestStruct {
771 name: alloc::string::String::from("a]relatively_long_name_for_testing_purposes"),
772 value: u64::MAX,
773 };
774 let empty = TestStruct {
775 name: alloc::string::String::new(),
776 value: 0,
777 };
778
779 v.push(&short).expect("push short");
780 v.push(&long).expect("push long");
781 v.push(&empty).expect("push empty");
782
783 assert_eq!(v.get(0).expect("get 0"), short);
784 assert_eq!(v.get(1).expect("get 1"), long);
785 assert_eq!(v.get(2).expect("get 2"), empty);
786
787 v.set(0, &long).expect("set 0 to long");
789 assert_eq!(v.get(0).expect("get 0 after set"), long);
790 }
791
792 #[test]
793 fn variable_size_element_exceeds_stride_returns_error() {
794 let lease = setup(4096);
798 let mut v: FabricVec<alloc::string::String> = FabricVec::new(lease, 16).expect("new");
799
800 let big = alloc::string::String::from("12345678901234567890");
802 assert_eq!(v.push(&big).unwrap_err(), FabricError::CapacityExceeded);
803 assert!(v.is_empty());
804 }
805
806 #[test]
807 fn capacity_boundary_fill_then_pop_then_refill() {
808 let lease = setup(88);
811 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
812 assert_eq!(v.capacity(), 4);
813
814 for i in 0..4u32 {
816 v.push(&(i * 10)).expect("push");
817 }
818 assert_eq!(v.len(), 4);
819 host::mock_set_fbmu_arena_size(0);
821 assert_eq!(v.push(&99).unwrap_err(), FabricError::CapacityExceeded);
822 host::mock_set_fbmu_arena_size(88);
824
825 for i in (0..4u32).rev() {
827 assert_eq!(v.pop().expect("pop"), Some(i * 10));
828 }
829 assert!(v.is_empty());
830
831 for i in 100..104u32 {
833 v.push(&i).expect("re-push");
834 }
835 assert_eq!(v.len(), 4);
836 for (idx, expected) in (100..104u32).enumerate() {
837 assert_eq!(v.get(idx).expect("get"), expected);
838 }
839 }
840
841 #[test]
842 fn arena_too_small_for_header() {
843 let lease = setup(16);
845 let result: core::result::Result<FabricVec<u32>, _> = FabricVec::new(lease, 16);
846 match result {
847 Err(FabricError::CapacityExceeded) => {}
848 other => panic!("expected CapacityExceeded, got {:?}", other.err()),
849 }
850 }
851
852 #[test]
853 fn set_out_of_bounds() {
854 let lease = setup(4096);
855 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
856 v.push(&42).expect("push");
857 assert_eq!(v.set(1, &99).unwrap_err(), FabricError::CapacityExceeded);
859 assert_eq!(v.get(0).expect("get"), 42);
861 }
862
863 #[test]
864 fn iter_size_hint() {
865 let lease = setup(4096);
866 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
867 for i in 0..5u32 {
868 v.push(&i).expect("push");
869 }
870 let mut iter = v.iter();
871 assert_eq!(iter.size_hint(), (5, Some(5)));
872 iter.next();
873 assert_eq!(iter.size_hint(), (4, Some(4)));
874 }
875
876 #[test]
879 fn grow_chains_new_lease() {
880 host::reset_mock();
882 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
884 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
885 assert_eq!(v.capacity(), 2);
886
887 v.push(&10).expect("push 10");
888 v.push(&20).expect("push 20");
889
890 host::mock_set_fbmu_arena_size(56);
892 v.push(&30).expect("push 30 (triggers grow)");
893 assert!(v.capacity() >= 3);
894 assert_eq!(v.len(), 3);
895
896 assert_eq!(v.get(0).expect("get 0"), 10);
897 assert_eq!(v.get(1).expect("get 1"), 20);
898 assert_eq!(v.get(2).expect("get 2"), 30);
899 }
900
901 #[test]
902 fn grow_multiple_overflow_regions() {
903 host::reset_mock();
904 host::mock_set_fbmu_arena_size(56);
906 let lease = MemBuilder::new().acquire().expect("acquire");
907 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
908 assert_eq!(v.capacity(), 2);
909
910 for i in 0..6u32 {
912 v.push(&(i * 10)).expect("push");
913 }
914 assert_eq!(v.len(), 6);
915 assert!(v.capacity() >= 6);
916
917 for i in 0..6u32 {
919 assert_eq!(v.get(i as usize).expect("get"), i * 10);
920 }
921
922 for i in (0..6u32).rev() {
924 assert_eq!(v.pop().expect("pop"), Some(i * 10));
925 }
926 assert!(v.is_empty());
927 }
928
929 #[test]
930 fn grow_iter_spans_regions() {
931 host::reset_mock();
932 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
934 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
935
936 for i in 0..5u32 {
937 v.push(&i).expect("push");
938 }
939 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
940 assert_eq!(collected, alloc::vec![0, 1, 2, 3, 4]);
941 }
942
943 #[test]
944 fn grow_set_in_overflow_region() {
945 host::reset_mock();
946 host::mock_set_fbmu_arena_size(56); let lease = MemBuilder::new().acquire().expect("acquire");
948 let mut v: FabricVec<u32> = FabricVec::new(lease, 16).expect("new");
949
950 v.push(&1).expect("push");
951 v.push(&2).expect("push");
952 v.push(&3).expect("push"); v.set(2, &99).expect("set in overflow");
955 assert_eq!(v.get(2).expect("get"), 99);
956 }
957
958 #[test]
961 fn fabric_vec_string_elements() {
962 let lease = setup(8192);
963 let mut v: FabricVec<alloc::string::String> = FabricVec::new(lease, 64).expect("new");
964
965 let strings = alloc::vec![
966 alloc::string::String::from("hello"),
967 alloc::string::String::from("world"),
968 alloc::string::String::from(""),
969 alloc::string::String::from("a longer string with more characters"),
970 ];
971 for s in &strings {
972 v.push(s).expect("push");
973 }
974 for (i, s) in strings.iter().enumerate() {
975 assert_eq!(&v.get(i).expect("get"), s);
976 }
977 }
978
979 #[test]
980 fn fabric_vec_vec_u8_elements() {
981 let lease = setup(8192);
982 let mut v: FabricVec<alloc::vec::Vec<u8>> = FabricVec::new(lease, 64).expect("new");
983
984 let items: alloc::vec::Vec<alloc::vec::Vec<u8>> =
985 alloc::vec![alloc::vec![1, 2, 3], alloc::vec![], alloc::vec![255; 50],];
986 for item in &items {
987 v.push(item).expect("push");
988 }
989 for (i, item) in items.iter().enumerate() {
990 assert_eq!(&v.get(i).expect("get"), item);
991 }
992 }
993
994 #[test]
997 fn var_vec_push_pop_roundtrip() {
998 let lease = setup(8192);
999 let mut v: VarFabricVec<alloc::string::String> =
1000 VarFabricVec::new(lease, 100).expect("new");
1001
1002 v.push(&alloc::string::String::from("short")).expect("push");
1003 v.push(&alloc::string::String::from(
1004 "a much longer string that takes more heap space",
1005 ))
1006 .expect("push");
1007 v.push(&alloc::string::String::from("")).expect("push");
1008 assert_eq!(v.len(), 3);
1009
1010 assert_eq!(
1011 v.get(0).expect("get 0"),
1012 alloc::string::String::from("short")
1013 );
1014 assert_eq!(
1015 v.get(1).expect("get 1"),
1016 alloc::string::String::from("a much longer string that takes more heap space")
1017 );
1018 assert_eq!(v.get(2).expect("get 2"), alloc::string::String::from(""));
1019
1020 assert_eq!(v.pop().expect("pop"), Some(alloc::string::String::from("")));
1021 assert_eq!(v.len(), 2);
1022 }
1023
1024 #[test]
1025 fn var_vec_mixed_sizes_efficient() {
1026 let lease = setup(8192);
1027 let mut v: VarFabricVec<alloc::vec::Vec<u8>> = VarFabricVec::new(lease, 100).expect("new");
1028
1029 v.push(&alloc::vec![42u8]).expect("push tiny");
1031 v.push(&alloc::vec![0u8; 100]).expect("push medium");
1032 v.push(&alloc::vec![255u8; 500]).expect("push large");
1033
1034 assert_eq!(v.len(), 3);
1035 assert_eq!(v.get(0).expect("get 0"), alloc::vec![42u8]);
1036 assert_eq!(v.get(1).expect("get 1"), alloc::vec![0u8; 100]);
1037 assert_eq!(v.get(2).expect("get 2"), alloc::vec![255u8; 500]);
1038
1039 assert!(v.heap_used() < 1000);
1042 }
1043
1044 #[test]
1045 fn var_vec_with_capacity() {
1046 host::reset_mock();
1047 host::mock_set_fbmu_arena_size(65536);
1048 let v: VarFabricVec<alloc::string::String> =
1049 VarFabricVec::with_capacity(50, 32).expect("with_capacity");
1050 assert_eq!(v.index_capacity(), 50);
1051 assert!(v.heap_size() > 0);
1052 }
1053
1054 #[test]
1055 fn var_vec_clear() {
1056 let lease = setup(8192);
1057 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 100).expect("new");
1058 v.push(&1).expect("push");
1059 v.push(&2).expect("push");
1060 v.clear().expect("clear");
1061 assert!(v.is_empty());
1062 assert_eq!(v.heap_used(), 0);
1063 }
1064
1065 #[test]
1066 fn var_vec_iter() {
1067 let lease = setup(8192);
1068 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 100).expect("new");
1069 for i in 0..5u32 {
1070 v.push(&(i * 10)).expect("push");
1071 }
1072 let collected: alloc::vec::Vec<u32> = v.iter().map(|r| r.expect("iter")).collect();
1073 assert_eq!(collected, alloc::vec![0, 10, 20, 30, 40]);
1074 }
1075
1076 #[test]
1077 fn var_vec_heap_full_returns_error() {
1078 let lease = setup(256);
1082 let mut v: VarFabricVec<alloc::vec::Vec<u8>> = VarFabricVec::new(lease, 10).expect("new");
1083 v.push(&alloc::vec![0u8; 60]).expect("push 1");
1085 let result = v.push(&alloc::vec![0u8; 60]);
1087 assert_eq!(result.unwrap_err(), FabricError::CapacityExceeded);
1088 assert_eq!(v.len(), 1);
1089 }
1090
1091 #[test]
1092 fn var_vec_index_full_returns_error() {
1093 let lease = setup(4096);
1096 let mut v: VarFabricVec<u32> = VarFabricVec::new(lease, 2).expect("new");
1097 v.push(&1).expect("push 1");
1098 v.push(&2).expect("push 2");
1099 assert_eq!(v.push(&3).unwrap_err(), FabricError::CapacityExceeded);
1100 }
1101
1102 #[test]
1103 fn var_vec_pop_reclaims_heap() {
1104 let lease = setup(8192);
1105 let mut v: VarFabricVec<alloc::string::String> =
1106 VarFabricVec::new(lease, 100).expect("new");
1107 v.push(&alloc::string::String::from("first")).expect("push");
1108 let after_first = v.heap_used();
1109 v.push(&alloc::string::String::from("second"))
1110 .expect("push");
1111 let after_second = v.heap_used();
1112 assert!(after_second > after_first);
1113
1114 v.pop().expect("pop");
1116 assert_eq!(v.heap_used(), after_first);
1117 }
1118}