1use super::heap_header::{HeapHeader, HEAP_KIND_V2_TYPED_ARRAY};
20use std::alloc::{Layout, alloc, dealloc, realloc};
21use std::ptr;
22
23#[repr(C)]
28pub struct TypedArray<T> {
29 pub header: HeapHeader,
31 pub data: *mut T,
33 pub len: u32,
35 pub cap: u32,
37}
38
39const _: () = {
41 assert!(std::mem::size_of::<TypedArray<f64>>() == 24);
42 assert!(std::mem::size_of::<TypedArray<i32>>() == 24);
43 assert!(std::mem::size_of::<TypedArray<u8>>() == 24);
44 assert!(std::mem::size_of::<TypedArray<f32>>() == 24);
46 assert!(std::mem::size_of::<TypedArray<char>>() == 24);
47};
48
49impl<T: Copy> TypedArray<T> {
50 pub fn new() -> *mut Self {
55 Self::with_capacity(0)
56 }
57
58 pub fn with_capacity(cap: u32) -> *mut Self {
62 let layout = Layout::new::<Self>();
63 let ptr = unsafe { alloc(layout) as *mut Self };
64 assert!(!ptr.is_null(), "allocation failed for TypedArray");
65
66 let data = if cap > 0 {
67 let data_layout = Layout::array::<T>(cap as usize).expect("invalid array layout");
68 let data_ptr = unsafe { alloc(data_layout) as *mut T };
69 assert!(!data_ptr.is_null(), "allocation failed for TypedArray data");
70 data_ptr
71 } else {
72 ptr::null_mut()
73 };
74
75 unsafe {
76 ptr::write(
77 ptr,
78 Self {
79 header: HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY),
80 data,
81 len: 0,
82 cap,
83 },
84 );
85 }
86
87 ptr
88 }
89
90 pub fn from_slice(slice: &[T]) -> *mut Self {
92 let len = slice.len() as u32;
93 let ptr = Self::with_capacity(len);
94 unsafe {
95 if len > 0 {
96 ptr::copy_nonoverlapping(slice.as_ptr(), (*ptr).data, slice.len());
97 }
98 (*ptr).len = len;
99 }
100 ptr
101 }
102
103 #[inline]
108 pub unsafe fn get(this: *const Self, index: u32) -> Option<T> {
109 unsafe {
110 if index >= (*this).len {
111 None
112 } else {
113 Some(ptr::read((*this).data.add(index as usize)))
114 }
115 }
116 }
117
118 #[inline]
124 pub unsafe fn get_unchecked(this: *const Self, index: u32) -> T {
125 unsafe { ptr::read((*this).data.add(index as usize)) }
126 }
127
128 #[inline]
133 pub unsafe fn set(this: *mut Self, index: u32, val: T) {
134 unsafe {
135 assert!(
136 index < (*this).len,
137 "TypedArray::set index {} out of bounds (len {})",
138 index,
139 (*this).len
140 );
141 ptr::write((*this).data.add(index as usize), val);
142 }
143 }
144
145 pub unsafe fn push(this: *mut Self, val: T) {
150 unsafe {
151 let arr = &mut *this;
152 if arr.len == arr.cap {
153 Self::grow(this);
154 }
155 let arr = &mut *this;
156 ptr::write(arr.data.add(arr.len as usize), val);
157 arr.len += 1;
158 }
159 }
160
161 pub unsafe fn pop(this: *mut Self) -> Option<T> {
166 unsafe {
167 let arr = &mut *this;
168 if arr.len == 0 {
169 None
170 } else {
171 arr.len -= 1;
172 Some(ptr::read(arr.data.add(arr.len as usize)))
173 }
174 }
175 }
176
177 #[inline]
182 pub unsafe fn len(this: *const Self) -> u32 {
183 unsafe { (*this).len }
184 }
185
186 #[inline]
191 pub unsafe fn capacity(this: *const Self) -> u32 {
192 unsafe { (*this).cap }
193 }
194
195 #[inline]
200 pub unsafe fn is_empty(this: *const Self) -> bool {
201 unsafe { (*this).len == 0 }
202 }
203
204 #[inline]
209 pub unsafe fn as_slice<'a>(this: *const Self) -> &'a [T] {
210 unsafe {
211 if (*this).len == 0 {
212 &[]
213 } else {
214 std::slice::from_raw_parts((*this).data, (*this).len as usize)
215 }
216 }
217 }
218
219 #[inline]
224 pub unsafe fn as_mut_slice<'a>(this: *mut Self) -> &'a mut [T] {
225 unsafe {
226 if (*this).len == 0 {
227 &mut []
228 } else {
229 std::slice::from_raw_parts_mut((*this).data, (*this).len as usize)
230 }
231 }
232 }
233
234 pub unsafe fn drop_array(ptr: *mut Self) {
240 unsafe {
241 let arr = &*ptr;
242 if arr.cap > 0 && !arr.data.is_null() {
244 let data_layout =
245 Layout::array::<T>(arr.cap as usize).expect("invalid array layout");
246 dealloc(arr.data as *mut u8, data_layout);
247 }
248 let layout = Layout::new::<Self>();
250 dealloc(ptr as *mut u8, layout);
251 }
252 }
253
254 unsafe fn grow(this: *mut Self) {
259 unsafe {
260 let arr = &mut *this;
261 let new_cap = if arr.cap == 0 {
262 4
263 } else {
264 arr.cap.checked_mul(2).expect("capacity overflow")
265 };
266 let new_layout = Layout::array::<T>(new_cap as usize).expect("invalid array layout");
267
268 let new_data = if arr.cap == 0 || arr.data.is_null() {
269 alloc(new_layout) as *mut T
270 } else {
271 let old_layout =
272 Layout::array::<T>(arr.cap as usize).expect("invalid array layout");
273 realloc(arr.data as *mut u8, old_layout, new_layout.size()) as *mut T
274 };
275 assert!(!new_data.is_null(), "reallocation failed for TypedArray");
276
277 arr.data = new_data;
278 arr.cap = new_cap;
279 }
280 }
281}
282
283impl<T: super::heap_element::HeapElement> TypedArray<*const T> {
297 pub unsafe fn drop_array_heap(ptr: *mut Self) {
306 unsafe {
307 let arr = &*ptr;
308 if arr.cap > 0 && !arr.data.is_null() {
309 for i in 0..arr.len {
311 let elem_ptr = ptr::read(arr.data.add(i as usize));
312 T::release_elem(elem_ptr);
313 }
314 let data_layout = Layout::array::<*const T>(arr.cap as usize)
316 .expect("invalid array layout");
317 dealloc(arr.data as *mut u8, data_layout);
318 }
319 let layout = Layout::new::<Self>();
321 dealloc(ptr as *mut u8, layout);
322 }
323 }
324}
325
326pub const ELEM_TYPE_UNKNOWN: u8 = 0;
346pub const ELEM_TYPE_F64: u8 = 1;
348pub const ELEM_TYPE_I64: u8 = 2;
350pub const ELEM_TYPE_I32: u8 = 3;
352pub const ELEM_TYPE_BOOL: u8 = 4;
354pub const ELEM_TYPE_I8: u8 = 5;
356pub const ELEM_TYPE_U8: u8 = 6;
358pub const ELEM_TYPE_I16: u8 = 7;
360pub const ELEM_TYPE_U16: u8 = 8;
362pub const ELEM_TYPE_U32: u8 = 9;
364pub const ELEM_TYPE_F32: u8 = 11;
367pub const ELEM_TYPE_CHAR: u8 = 12;
369pub const ELEM_TYPE_STRING: u8 = 13;
371pub const ELEM_TYPE_DECIMAL: u8 = 14;
373pub const ELEM_TYPE_TYPED_OBJECT: u8 = 15;
375
376#[inline]
381pub unsafe fn read_elem_type(ptr: *const u8) -> u8 {
382 unsafe { *ptr.add(7) }
383}
384
385#[inline]
397pub unsafe fn retain_v2_typed_array(ptr: *mut u8) {
398 unsafe { super::refcount::v2_retain(ptr as *const HeapHeader) };
399}
400
401pub unsafe fn release_v2_typed_array(ptr: *mut u8) {
417 unsafe {
418 if !super::refcount::v2_release(ptr as *const HeapHeader) {
419 return;
420 }
421 match read_elem_type(ptr) {
423 ELEM_TYPE_F64 => TypedArray::<f64>::drop_array(ptr as *mut TypedArray<f64>),
424 ELEM_TYPE_I64 => TypedArray::<i64>::drop_array(ptr as *mut TypedArray<i64>),
425 ELEM_TYPE_I32 => TypedArray::<i32>::drop_array(ptr as *mut TypedArray<i32>),
426 ELEM_TYPE_BOOL | ELEM_TYPE_U8 => {
427 TypedArray::<u8>::drop_array(ptr as *mut TypedArray<u8>)
428 }
429 ELEM_TYPE_I8 => TypedArray::<i8>::drop_array(ptr as *mut TypedArray<i8>),
430 ELEM_TYPE_I16 => TypedArray::<i16>::drop_array(ptr as *mut TypedArray<i16>),
431 ELEM_TYPE_U16 => TypedArray::<u16>::drop_array(ptr as *mut TypedArray<u16>),
432 ELEM_TYPE_U32 => TypedArray::<u32>::drop_array(ptr as *mut TypedArray<u32>),
433 ELEM_TYPE_F32 => TypedArray::<f32>::drop_array(ptr as *mut TypedArray<f32>),
434 ELEM_TYPE_CHAR => TypedArray::<char>::drop_array(ptr as *mut TypedArray<char>),
435 ELEM_TYPE_STRING => {
436 TypedArray::<*const super::string_obj::StringObj>::drop_array_heap(
437 ptr as *mut TypedArray<*const super::string_obj::StringObj>,
438 )
439 }
440 ELEM_TYPE_DECIMAL => {
441 TypedArray::<*const super::decimal_obj::DecimalObj>::drop_array_heap(
442 ptr as *mut TypedArray<*const super::decimal_obj::DecimalObj>,
443 )
444 }
445 ELEM_TYPE_TYPED_OBJECT => {
446 TypedArray::<*const crate::heap_value::TypedObjectStorage>::drop_array_heap(
447 ptr as *mut TypedArray<*const crate::heap_value::TypedObjectStorage>,
448 )
449 }
450 other => {
458 debug_assert!(
459 false,
460 "release_v2_typed_array: TypedArray at {:p} has unstamped \
461 element-type discriminant {} — producer-side stamp_elem_type \
462 contract violated (ADR-006 §2.7.7)",
463 ptr, other
464 );
465 let layout = Layout::new::<TypedArray<u8>>();
466 dealloc(ptr, layout);
467 }
468 }
469 }
470}
471
472impl<T> TypedArray<T> {
485 #[doc(alias = "new")]
492 pub fn new_generic() -> *mut Self {
493 Self::with_capacity_generic(0)
494 }
495
496 #[doc(alias = "with_capacity")]
502 pub fn with_capacity_generic(cap: u32) -> *mut Self {
503 let layout = Layout::new::<Self>();
504 let ptr = unsafe { alloc(layout) as *mut Self };
505 assert!(!ptr.is_null(), "allocation failed for TypedArray");
506
507 let data = if cap > 0 {
508 let data_layout = Layout::array::<T>(cap as usize).expect("invalid array layout");
509 let data_ptr = unsafe { alloc(data_layout) as *mut T };
510 assert!(!data_ptr.is_null(), "allocation failed for TypedArray data");
511 data_ptr
512 } else {
513 ptr::null_mut()
514 };
515
516 unsafe {
517 ptr::write(
518 ptr,
519 Self {
520 header: HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY),
521 data,
522 len: 0,
523 cap,
524 },
525 );
526 }
527
528 ptr
529 }
530
531 #[inline]
536 pub unsafe fn len_generic(this: *const Self) -> u32 {
537 unsafe { (*this).len }
538 }
539
540 #[inline]
545 pub unsafe fn capacity_generic(this: *const Self) -> u32 {
546 unsafe { (*this).cap }
547 }
548
549 #[inline]
554 pub unsafe fn is_empty_generic(this: *const Self) -> bool {
555 unsafe { (*this).len == 0 }
556 }
557
558 #[inline]
563 pub unsafe fn as_slice_generic<'a>(this: *const Self) -> &'a [T] {
564 unsafe {
565 if (*this).len == 0 {
566 &[]
567 } else {
568 std::slice::from_raw_parts((*this).data, (*this).len as usize)
569 }
570 }
571 }
572}
573
574#[cfg(test)]
575mod tests {
576 use super::*;
577
578 #[test]
579 fn test_size_of_typed_array() {
580 assert_eq!(std::mem::size_of::<TypedArray<f64>>(), 24);
581 assert_eq!(std::mem::size_of::<TypedArray<i32>>(), 24);
582 assert_eq!(std::mem::size_of::<TypedArray<i64>>(), 24);
583 assert_eq!(std::mem::size_of::<TypedArray<u8>>(), 24);
584 }
585
586 #[test]
587 fn test_field_offsets() {
588 let arr = TypedArray::<f64>::with_capacity(0);
589 unsafe {
590 let base = arr as *const u8 as usize;
591 let header_offset = &(*arr).header as *const _ as usize - base;
592 let data_offset = &(*arr).data as *const _ as usize - base;
593 let len_offset = &(*arr).len as *const _ as usize - base;
594 let cap_offset = &(*arr).cap as *const _ as usize - base;
595
596 assert_eq!(header_offset, 0);
597 assert_eq!(data_offset, 8);
598 assert_eq!(len_offset, 16);
599 assert_eq!(cap_offset, 20);
600
601 TypedArray::drop_array(arr);
602 }
603 }
604
605 #[test]
606 fn test_new_empty() {
607 let arr = TypedArray::<f64>::new();
608 unsafe {
609 assert_eq!(TypedArray::len(arr), 0);
610 assert_eq!(TypedArray::capacity(arr), 0);
611 assert!(TypedArray::is_empty(arr));
612 assert_eq!((*arr).header.kind(), HEAP_KIND_V2_TYPED_ARRAY);
613 assert_eq!((*arr).header.get_refcount(), 1);
614 TypedArray::drop_array(arr);
615 }
616 }
617
618 #[test]
619 fn test_with_capacity() {
620 let arr = TypedArray::<f64>::with_capacity(16);
621 unsafe {
622 assert_eq!(TypedArray::len(arr), 0);
623 assert_eq!(TypedArray::capacity(arr), 16);
624 assert!(TypedArray::is_empty(arr));
625 TypedArray::drop_array(arr);
626 }
627 }
628
629 #[test]
630 fn test_push_and_get_f64() {
631 let arr = TypedArray::<f64>::new();
632 unsafe {
633 TypedArray::push(arr, 1.0);
634 TypedArray::push(arr, 2.5);
635 TypedArray::push(arr, 3.14);
636
637 assert_eq!(TypedArray::len(arr), 3);
638 assert!(!TypedArray::is_empty(arr));
639
640 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
641 assert_eq!(TypedArray::get(arr, 1), Some(2.5));
642 assert_eq!(TypedArray::get(arr, 2), Some(3.14));
643 assert_eq!(TypedArray::get(arr, 3), None); TypedArray::drop_array(arr);
646 }
647 }
648
649 #[test]
650 fn test_push_and_get_i32() {
651 let arr = TypedArray::<i32>::new();
652 unsafe {
653 TypedArray::push(arr, 42);
654 TypedArray::push(arr, -7);
655 TypedArray::push(arr, 0);
656
657 assert_eq!(TypedArray::len(arr), 3);
658 assert_eq!(TypedArray::get(arr, 0), Some(42));
659 assert_eq!(TypedArray::get(arr, 1), Some(-7));
660 assert_eq!(TypedArray::get(arr, 2), Some(0));
661 assert_eq!(TypedArray::get(arr, 3), None);
662
663 TypedArray::drop_array(arr);
664 }
665 }
666
667 #[test]
668 fn test_push_and_get_i64() {
669 let arr = TypedArray::<i64>::new();
670 unsafe {
671 TypedArray::push(arr, i64::MAX);
672 TypedArray::push(arr, i64::MIN);
673
674 assert_eq!(TypedArray::get(arr, 0), Some(i64::MAX));
675 assert_eq!(TypedArray::get(arr, 1), Some(i64::MIN));
676
677 TypedArray::drop_array(arr);
678 }
679 }
680
681 #[test]
682 fn test_push_and_get_u8_bool() {
683 let arr = TypedArray::<u8>::new();
684 unsafe {
685 TypedArray::push(arr, 1u8); TypedArray::push(arr, 0u8); TypedArray::push(arr, 1u8); assert_eq!(TypedArray::len(arr), 3);
690 assert_eq!(TypedArray::get(arr, 0), Some(1));
691 assert_eq!(TypedArray::get(arr, 1), Some(0));
692 assert_eq!(TypedArray::get(arr, 2), Some(1));
693
694 TypedArray::drop_array(arr);
695 }
696 }
697
698 #[test]
699 fn test_get_unchecked() {
700 let arr = TypedArray::<f64>::from_slice(&[10.0, 20.0, 30.0]);
701 unsafe {
702 assert_eq!(TypedArray::get_unchecked(arr, 0), 10.0);
703 assert_eq!(TypedArray::get_unchecked(arr, 1), 20.0);
704 assert_eq!(TypedArray::get_unchecked(arr, 2), 30.0);
705 TypedArray::drop_array(arr);
706 }
707 }
708
709 #[test]
710 fn test_set() {
711 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0, 3.0]);
712 unsafe {
713 TypedArray::set(arr, 1, 99.0);
714 assert_eq!(TypedArray::get(arr, 1), Some(99.0));
715
716 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
718 assert_eq!(TypedArray::get(arr, 2), Some(3.0));
719
720 TypedArray::drop_array(arr);
721 }
722 }
723
724 #[test]
725 #[should_panic(expected = "out of bounds")]
726 fn test_set_out_of_bounds() {
727 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0]);
728 unsafe {
729 TypedArray::set(arr, 5, 99.0);
730 }
732 }
733
734 #[test]
735 fn test_pop() {
736 let arr = TypedArray::<i32>::from_slice(&[10, 20, 30]);
737 unsafe {
738 assert_eq!(TypedArray::pop(arr), Some(30));
739 assert_eq!(TypedArray::len(arr), 2);
740
741 assert_eq!(TypedArray::pop(arr), Some(20));
742 assert_eq!(TypedArray::len(arr), 1);
743
744 assert_eq!(TypedArray::pop(arr), Some(10));
745 assert_eq!(TypedArray::len(arr), 0);
746
747 assert_eq!(TypedArray::pop(arr), None);
748 assert!(TypedArray::is_empty(arr));
749
750 TypedArray::drop_array(arr);
751 }
752 }
753
754 #[test]
755 fn test_from_slice() {
756 let data = [1.0f64, 2.0, 3.0, 4.0, 5.0];
757 let arr = TypedArray::from_slice(&data);
758 unsafe {
759 assert_eq!(TypedArray::len(arr), 5);
760 assert_eq!(TypedArray::capacity(arr), 5);
761
762 for (i, &expected) in data.iter().enumerate() {
763 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
764 }
765
766 TypedArray::drop_array(arr);
767 }
768 }
769
770 #[test]
771 fn test_from_empty_slice() {
772 let arr = TypedArray::<f64>::from_slice(&[]);
773 unsafe {
774 assert_eq!(TypedArray::len(arr), 0);
775 assert_eq!(TypedArray::capacity(arr), 0);
776 assert!(TypedArray::is_empty(arr));
777 TypedArray::drop_array(arr);
778 }
779 }
780
781 #[test]
782 fn test_as_slice() {
783 let arr = TypedArray::from_slice(&[10i32, 20, 30]);
784 unsafe {
785 let s = TypedArray::as_slice(arr);
786 assert_eq!(s, &[10, 20, 30]);
787 TypedArray::drop_array(arr);
788 }
789 }
790
791 #[test]
792 fn test_as_mut_slice() {
793 let arr = TypedArray::from_slice(&[1.0f64, 2.0, 3.0]);
794 unsafe {
795 let s = TypedArray::as_mut_slice(arr);
796 s[1] = 99.0;
797 assert_eq!(TypedArray::get(arr, 1), Some(99.0));
798 TypedArray::drop_array(arr);
799 }
800 }
801
802 #[test]
803 fn test_as_slice_empty() {
804 let arr = TypedArray::<f64>::new();
805 unsafe {
806 let s = TypedArray::as_slice(arr);
807 assert!(s.is_empty());
808 TypedArray::drop_array(arr);
809 }
810 }
811
812 #[test]
813 fn test_capacity_growth() {
814 let arr = TypedArray::<f64>::new();
815 unsafe {
816 TypedArray::push(arr, 1.0);
818 assert!(TypedArray::capacity(arr) >= 1);
819
820 for i in 2..=20 {
822 TypedArray::push(arr, i as f64);
823 }
824 assert_eq!(TypedArray::len(arr), 20);
825
826 for i in 0..20 {
828 assert_eq!(TypedArray::get(arr, i), Some((i + 1) as f64));
829 }
830
831 TypedArray::drop_array(arr);
832 }
833 }
834
835 #[test]
836 fn test_header_kind() {
837 let arr = TypedArray::<f64>::new();
838 unsafe {
839 assert_eq!((*arr).header.kind(), HEAP_KIND_V2_TYPED_ARRAY);
840 assert_eq!((*arr).header.get_refcount(), 1);
841 TypedArray::drop_array(arr);
842 }
843 }
844
845 #[test]
846 fn test_drop_safety() {
847 unsafe {
849 for _ in 0..100 {
850 let arr = TypedArray::<f64>::new();
851 for i in 0..50 {
852 TypedArray::push(arr, i as f64);
853 }
854 TypedArray::drop_array(arr);
855 }
856 for _ in 0..100 {
858 let arr = TypedArray::<i32>::new();
859 TypedArray::drop_array(arr);
860 }
861 }
862 }
863
864 #[test]
865 fn test_get_out_of_bounds_returns_none() {
866 let arr = TypedArray::<f64>::new();
867 unsafe {
868 assert_eq!(TypedArray::get(arr, 0), None);
870 assert_eq!(TypedArray::get(arr, 100), None);
871 assert_eq!(TypedArray::get(arr, u32::MAX), None);
872
873 TypedArray::push(arr, 1.0);
874 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
875 assert_eq!(TypedArray::get(arr, 1), None);
876
877 TypedArray::drop_array(arr);
878 }
879 }
880
881 #[test]
882 fn test_refcount_with_typed_array() {
883 use crate::v2::refcount::{v2_get_refcount, v2_retain, v2_release};
884
885 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0]);
886 unsafe {
887 let header_ptr = arr as *const HeapHeader;
888
889 assert_eq!(v2_get_refcount(header_ptr), 1);
890
891 v2_retain(header_ptr);
892 assert_eq!(v2_get_refcount(header_ptr), 2);
893
894 assert!(!v2_release(header_ptr)); assert_eq!(v2_get_refcount(header_ptr), 1);
896
897 TypedArray::drop_array(arr);
899 }
900 }
901
902 #[test]
908 fn test_drop_array_heap_string_obj() {
909 use crate::v2::string_obj::StringObj;
910 unsafe {
911 let arr: *mut TypedArray<*const StringObj> = TypedArray::with_capacity(4);
913 let s1 = StringObj::new("hello");
915 let s2 = StringObj::new("world");
916 let s3 = StringObj::new("!");
917 TypedArray::push(arr, s1 as *const StringObj);
918 TypedArray::push(arr, s2 as *const StringObj);
919 TypedArray::push(arr, s3 as *const StringObj);
920 assert_eq!(TypedArray::len(arr), 3);
921 TypedArray::<*const StringObj>::drop_array_heap(arr);
924 }
925 }
926
927 #[test]
928 fn test_drop_array_heap_decimal_obj() {
929 use crate::v2::decimal_obj::DecimalObj;
930 use rust_decimal::Decimal;
931 use rust_decimal::prelude::FromPrimitive;
932 unsafe {
933 let arr: *mut TypedArray<*const DecimalObj> = TypedArray::with_capacity(4);
934 let d1 = DecimalObj::new(Decimal::from_f64(1.5).unwrap());
935 let d2 = DecimalObj::new(Decimal::from_f64(2.5).unwrap());
936 let d3 = DecimalObj::new(Decimal::ZERO);
937 TypedArray::push(arr, d1 as *const DecimalObj);
938 TypedArray::push(arr, d2 as *const DecimalObj);
939 TypedArray::push(arr, d3 as *const DecimalObj);
940 assert_eq!(TypedArray::len(arr), 3);
941 TypedArray::<*const DecimalObj>::drop_array_heap(arr);
942 }
943 }
944
945 #[test]
946 fn test_drop_array_heap_empty() {
947 use crate::v2::string_obj::StringObj;
948 unsafe {
949 let arr: *mut TypedArray<*const StringObj> = TypedArray::new();
951 TypedArray::<*const StringObj>::drop_array_heap(arr);
952 }
953 }
954
955 #[test]
960 fn test_size_of_typed_array_f32_char() {
961 assert_eq!(std::mem::size_of::<TypedArray<f32>>(), 24);
962 assert_eq!(std::mem::size_of::<TypedArray<char>>(), 24);
963 }
964
965 #[test]
966 fn test_push_and_get_f32() {
967 let arr = TypedArray::<f32>::new();
968 unsafe {
969 TypedArray::push(arr, 1.5_f32);
970 TypedArray::push(arr, 2.25_f32);
971 TypedArray::push(arr, std::f32::consts::PI);
972 assert_eq!(TypedArray::len(arr), 3);
973 assert_eq!(TypedArray::get(arr, 0), Some(1.5_f32));
974 assert_eq!(TypedArray::get(arr, 1), Some(2.25_f32));
975 assert_eq!(TypedArray::get(arr, 2), Some(std::f32::consts::PI));
976 assert_eq!(TypedArray::get(arr, 3), None);
977 TypedArray::drop_array(arr);
978 }
979 }
980
981 #[test]
982 fn test_push_and_get_char() {
983 let arr = TypedArray::<char>::new();
984 unsafe {
985 TypedArray::push(arr, 'a');
986 TypedArray::push(arr, '☃');
987 TypedArray::push(arr, '👋');
988 assert_eq!(TypedArray::len(arr), 3);
989 assert_eq!(TypedArray::get(arr, 0), Some('a'));
990 assert_eq!(TypedArray::get(arr, 1), Some('☃'));
991 assert_eq!(TypedArray::get(arr, 2), Some('👋'));
992 assert_eq!(TypedArray::get(arr, 3), None);
993 TypedArray::drop_array(arr);
994 }
995 }
996
997 #[test]
998 fn test_from_slice_f32() {
999 let data: [f32; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];
1000 let arr = TypedArray::from_slice(&data);
1001 unsafe {
1002 assert_eq!(TypedArray::len(arr), 5);
1003 for (i, &expected) in data.iter().enumerate() {
1004 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
1005 }
1006 TypedArray::drop_array(arr);
1007 }
1008 }
1009
1010 #[test]
1011 fn test_from_slice_char() {
1012 let data = ['h', 'i', '!'];
1013 let arr = TypedArray::from_slice(&data);
1014 unsafe {
1015 assert_eq!(TypedArray::len(arr), 3);
1016 for (i, &expected) in data.iter().enumerate() {
1017 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
1018 }
1019 TypedArray::drop_array(arr);
1020 }
1021 }
1022
1023 #[test]
1024 fn test_drop_array_heap_with_held_share() {
1025 use crate::v2::refcount::{v2_get_refcount, v2_retain};
1026 use crate::v2::string_obj::StringObj;
1027 unsafe {
1028 let arr: *mut TypedArray<*const StringObj> = TypedArray::with_capacity(2);
1031 let s = StringObj::new("shared");
1032 v2_retain(&(*s).header); TypedArray::push(arr, s as *const StringObj);
1034
1035 TypedArray::<*const StringObj>::drop_array_heap(arr);
1036
1037 assert_eq!(v2_get_refcount(&(*s).header), 1);
1039 assert_eq!(StringObj::as_str(s), "shared");
1040 StringObj::drop(s);
1042 }
1043 }
1044
1045 #[test]
1051 fn release_v2_typed_array_pod_drop_balance() {
1052 use crate::v2::refcount::v2_get_refcount;
1053 unsafe {
1054 let arr = TypedArray::<i64>::with_capacity(4);
1055 TypedArray::push(arr, 10);
1056 TypedArray::push(arr, 20);
1057 TypedArray::push(arr, 30);
1058 super::stamp_elem_type_for_test(arr as *mut u8, ELEM_TYPE_I64);
1059 let hdr = arr as *const HeapHeader;
1060 assert_eq!(v2_get_refcount(hdr), 1);
1061
1062 retain_v2_typed_array(arr as *mut u8);
1064 assert_eq!(v2_get_refcount(hdr), 2);
1065
1066 release_v2_typed_array(arr as *mut u8);
1068 assert_eq!(v2_get_refcount(hdr), 1);
1069 assert_eq!(TypedArray::get(arr, 1), Some(20));
1071
1072 release_v2_typed_array(arr as *mut u8);
1075 }
1076 }
1077
1078 #[test]
1083 fn release_v2_typed_array_heap_elem_drop_balance() {
1084 use crate::v2::refcount::{v2_get_refcount, v2_retain};
1085 use crate::v2::string_obj::StringObj;
1086 unsafe {
1087 let arr = TypedArray::<*const StringObj>::with_capacity(2);
1088 super::stamp_elem_type_for_test(arr as *mut u8, ELEM_TYPE_STRING);
1089 let s = StringObj::new("kept");
1090 v2_retain(&(*s).header); TypedArray::push(arr, s as *const StringObj);
1092
1093 retain_v2_typed_array(arr as *mut u8); release_v2_typed_array(arr as *mut u8); assert_eq!(StringObj::as_str(s), "kept");
1096
1097 release_v2_typed_array(arr as *mut u8);
1100 assert_eq!(v2_get_refcount(&(*s).header), 1);
1101 StringObj::drop(s);
1102 }
1103 }
1104
1105 #[test]
1108 fn release_v2_typed_array_repeated_cycle_balances() {
1109 use crate::v2::refcount::v2_get_refcount;
1110 unsafe {
1111 let arr = TypedArray::<i64>::with_capacity(1);
1112 TypedArray::push(arr, 99);
1113 super::stamp_elem_type_for_test(arr as *mut u8, ELEM_TYPE_I64);
1114 let hdr = arr as *const HeapHeader;
1115 for _ in 0..1000 {
1116 retain_v2_typed_array(arr as *mut u8);
1117 release_v2_typed_array(arr as *mut u8);
1118 }
1119 assert_eq!(v2_get_refcount(hdr), 1);
1120 assert_eq!(TypedArray::get(arr, 0), Some(99));
1121 release_v2_typed_array(arr as *mut u8);
1122 }
1123 }
1124}
1125
1126#[cfg(test)]
1131pub(crate) unsafe fn stamp_elem_type_for_test(ptr: *mut u8, elem_type: u8) {
1132 if ptr.is_null() {
1133 return;
1134 }
1135 unsafe {
1136 *ptr.add(7) = elem_type;
1137 }
1138}