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
326impl<T> TypedArray<T> {
339 #[doc(alias = "new")]
346 pub fn new_generic() -> *mut Self {
347 Self::with_capacity_generic(0)
348 }
349
350 #[doc(alias = "with_capacity")]
356 pub fn with_capacity_generic(cap: u32) -> *mut Self {
357 let layout = Layout::new::<Self>();
358 let ptr = unsafe { alloc(layout) as *mut Self };
359 assert!(!ptr.is_null(), "allocation failed for TypedArray");
360
361 let data = if cap > 0 {
362 let data_layout = Layout::array::<T>(cap as usize).expect("invalid array layout");
363 let data_ptr = unsafe { alloc(data_layout) as *mut T };
364 assert!(!data_ptr.is_null(), "allocation failed for TypedArray data");
365 data_ptr
366 } else {
367 ptr::null_mut()
368 };
369
370 unsafe {
371 ptr::write(
372 ptr,
373 Self {
374 header: HeapHeader::new(HEAP_KIND_V2_TYPED_ARRAY),
375 data,
376 len: 0,
377 cap,
378 },
379 );
380 }
381
382 ptr
383 }
384
385 #[inline]
390 pub unsafe fn len_generic(this: *const Self) -> u32 {
391 unsafe { (*this).len }
392 }
393
394 #[inline]
399 pub unsafe fn capacity_generic(this: *const Self) -> u32 {
400 unsafe { (*this).cap }
401 }
402
403 #[inline]
408 pub unsafe fn is_empty_generic(this: *const Self) -> bool {
409 unsafe { (*this).len == 0 }
410 }
411
412 #[inline]
417 pub unsafe fn as_slice_generic<'a>(this: *const Self) -> &'a [T] {
418 unsafe {
419 if (*this).len == 0 {
420 &[]
421 } else {
422 std::slice::from_raw_parts((*this).data, (*this).len as usize)
423 }
424 }
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 fn test_size_of_typed_array() {
434 assert_eq!(std::mem::size_of::<TypedArray<f64>>(), 24);
435 assert_eq!(std::mem::size_of::<TypedArray<i32>>(), 24);
436 assert_eq!(std::mem::size_of::<TypedArray<i64>>(), 24);
437 assert_eq!(std::mem::size_of::<TypedArray<u8>>(), 24);
438 }
439
440 #[test]
441 fn test_field_offsets() {
442 let arr = TypedArray::<f64>::with_capacity(0);
443 unsafe {
444 let base = arr as *const u8 as usize;
445 let header_offset = &(*arr).header as *const _ as usize - base;
446 let data_offset = &(*arr).data as *const _ as usize - base;
447 let len_offset = &(*arr).len as *const _ as usize - base;
448 let cap_offset = &(*arr).cap as *const _ as usize - base;
449
450 assert_eq!(header_offset, 0);
451 assert_eq!(data_offset, 8);
452 assert_eq!(len_offset, 16);
453 assert_eq!(cap_offset, 20);
454
455 TypedArray::drop_array(arr);
456 }
457 }
458
459 #[test]
460 fn test_new_empty() {
461 let arr = TypedArray::<f64>::new();
462 unsafe {
463 assert_eq!(TypedArray::len(arr), 0);
464 assert_eq!(TypedArray::capacity(arr), 0);
465 assert!(TypedArray::is_empty(arr));
466 assert_eq!((*arr).header.kind(), HEAP_KIND_V2_TYPED_ARRAY);
467 assert_eq!((*arr).header.get_refcount(), 1);
468 TypedArray::drop_array(arr);
469 }
470 }
471
472 #[test]
473 fn test_with_capacity() {
474 let arr = TypedArray::<f64>::with_capacity(16);
475 unsafe {
476 assert_eq!(TypedArray::len(arr), 0);
477 assert_eq!(TypedArray::capacity(arr), 16);
478 assert!(TypedArray::is_empty(arr));
479 TypedArray::drop_array(arr);
480 }
481 }
482
483 #[test]
484 fn test_push_and_get_f64() {
485 let arr = TypedArray::<f64>::new();
486 unsafe {
487 TypedArray::push(arr, 1.0);
488 TypedArray::push(arr, 2.5);
489 TypedArray::push(arr, 3.14);
490
491 assert_eq!(TypedArray::len(arr), 3);
492 assert!(!TypedArray::is_empty(arr));
493
494 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
495 assert_eq!(TypedArray::get(arr, 1), Some(2.5));
496 assert_eq!(TypedArray::get(arr, 2), Some(3.14));
497 assert_eq!(TypedArray::get(arr, 3), None); TypedArray::drop_array(arr);
500 }
501 }
502
503 #[test]
504 fn test_push_and_get_i32() {
505 let arr = TypedArray::<i32>::new();
506 unsafe {
507 TypedArray::push(arr, 42);
508 TypedArray::push(arr, -7);
509 TypedArray::push(arr, 0);
510
511 assert_eq!(TypedArray::len(arr), 3);
512 assert_eq!(TypedArray::get(arr, 0), Some(42));
513 assert_eq!(TypedArray::get(arr, 1), Some(-7));
514 assert_eq!(TypedArray::get(arr, 2), Some(0));
515 assert_eq!(TypedArray::get(arr, 3), None);
516
517 TypedArray::drop_array(arr);
518 }
519 }
520
521 #[test]
522 fn test_push_and_get_i64() {
523 let arr = TypedArray::<i64>::new();
524 unsafe {
525 TypedArray::push(arr, i64::MAX);
526 TypedArray::push(arr, i64::MIN);
527
528 assert_eq!(TypedArray::get(arr, 0), Some(i64::MAX));
529 assert_eq!(TypedArray::get(arr, 1), Some(i64::MIN));
530
531 TypedArray::drop_array(arr);
532 }
533 }
534
535 #[test]
536 fn test_push_and_get_u8_bool() {
537 let arr = TypedArray::<u8>::new();
538 unsafe {
539 TypedArray::push(arr, 1u8); TypedArray::push(arr, 0u8); TypedArray::push(arr, 1u8); assert_eq!(TypedArray::len(arr), 3);
544 assert_eq!(TypedArray::get(arr, 0), Some(1));
545 assert_eq!(TypedArray::get(arr, 1), Some(0));
546 assert_eq!(TypedArray::get(arr, 2), Some(1));
547
548 TypedArray::drop_array(arr);
549 }
550 }
551
552 #[test]
553 fn test_get_unchecked() {
554 let arr = TypedArray::<f64>::from_slice(&[10.0, 20.0, 30.0]);
555 unsafe {
556 assert_eq!(TypedArray::get_unchecked(arr, 0), 10.0);
557 assert_eq!(TypedArray::get_unchecked(arr, 1), 20.0);
558 assert_eq!(TypedArray::get_unchecked(arr, 2), 30.0);
559 TypedArray::drop_array(arr);
560 }
561 }
562
563 #[test]
564 fn test_set() {
565 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0, 3.0]);
566 unsafe {
567 TypedArray::set(arr, 1, 99.0);
568 assert_eq!(TypedArray::get(arr, 1), Some(99.0));
569
570 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
572 assert_eq!(TypedArray::get(arr, 2), Some(3.0));
573
574 TypedArray::drop_array(arr);
575 }
576 }
577
578 #[test]
579 #[should_panic(expected = "out of bounds")]
580 fn test_set_out_of_bounds() {
581 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0]);
582 unsafe {
583 TypedArray::set(arr, 5, 99.0);
584 }
586 }
587
588 #[test]
589 fn test_pop() {
590 let arr = TypedArray::<i32>::from_slice(&[10, 20, 30]);
591 unsafe {
592 assert_eq!(TypedArray::pop(arr), Some(30));
593 assert_eq!(TypedArray::len(arr), 2);
594
595 assert_eq!(TypedArray::pop(arr), Some(20));
596 assert_eq!(TypedArray::len(arr), 1);
597
598 assert_eq!(TypedArray::pop(arr), Some(10));
599 assert_eq!(TypedArray::len(arr), 0);
600
601 assert_eq!(TypedArray::pop(arr), None);
602 assert!(TypedArray::is_empty(arr));
603
604 TypedArray::drop_array(arr);
605 }
606 }
607
608 #[test]
609 fn test_from_slice() {
610 let data = [1.0f64, 2.0, 3.0, 4.0, 5.0];
611 let arr = TypedArray::from_slice(&data);
612 unsafe {
613 assert_eq!(TypedArray::len(arr), 5);
614 assert_eq!(TypedArray::capacity(arr), 5);
615
616 for (i, &expected) in data.iter().enumerate() {
617 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
618 }
619
620 TypedArray::drop_array(arr);
621 }
622 }
623
624 #[test]
625 fn test_from_empty_slice() {
626 let arr = TypedArray::<f64>::from_slice(&[]);
627 unsafe {
628 assert_eq!(TypedArray::len(arr), 0);
629 assert_eq!(TypedArray::capacity(arr), 0);
630 assert!(TypedArray::is_empty(arr));
631 TypedArray::drop_array(arr);
632 }
633 }
634
635 #[test]
636 fn test_as_slice() {
637 let arr = TypedArray::from_slice(&[10i32, 20, 30]);
638 unsafe {
639 let s = TypedArray::as_slice(arr);
640 assert_eq!(s, &[10, 20, 30]);
641 TypedArray::drop_array(arr);
642 }
643 }
644
645 #[test]
646 fn test_as_mut_slice() {
647 let arr = TypedArray::from_slice(&[1.0f64, 2.0, 3.0]);
648 unsafe {
649 let s = TypedArray::as_mut_slice(arr);
650 s[1] = 99.0;
651 assert_eq!(TypedArray::get(arr, 1), Some(99.0));
652 TypedArray::drop_array(arr);
653 }
654 }
655
656 #[test]
657 fn test_as_slice_empty() {
658 let arr = TypedArray::<f64>::new();
659 unsafe {
660 let s = TypedArray::as_slice(arr);
661 assert!(s.is_empty());
662 TypedArray::drop_array(arr);
663 }
664 }
665
666 #[test]
667 fn test_capacity_growth() {
668 let arr = TypedArray::<f64>::new();
669 unsafe {
670 TypedArray::push(arr, 1.0);
672 assert!(TypedArray::capacity(arr) >= 1);
673
674 for i in 2..=20 {
676 TypedArray::push(arr, i as f64);
677 }
678 assert_eq!(TypedArray::len(arr), 20);
679
680 for i in 0..20 {
682 assert_eq!(TypedArray::get(arr, i), Some((i + 1) as f64));
683 }
684
685 TypedArray::drop_array(arr);
686 }
687 }
688
689 #[test]
690 fn test_header_kind() {
691 let arr = TypedArray::<f64>::new();
692 unsafe {
693 assert_eq!((*arr).header.kind(), HEAP_KIND_V2_TYPED_ARRAY);
694 assert_eq!((*arr).header.get_refcount(), 1);
695 TypedArray::drop_array(arr);
696 }
697 }
698
699 #[test]
700 fn test_drop_safety() {
701 unsafe {
703 for _ in 0..100 {
704 let arr = TypedArray::<f64>::new();
705 for i in 0..50 {
706 TypedArray::push(arr, i as f64);
707 }
708 TypedArray::drop_array(arr);
709 }
710 for _ in 0..100 {
712 let arr = TypedArray::<i32>::new();
713 TypedArray::drop_array(arr);
714 }
715 }
716 }
717
718 #[test]
719 fn test_get_out_of_bounds_returns_none() {
720 let arr = TypedArray::<f64>::new();
721 unsafe {
722 assert_eq!(TypedArray::get(arr, 0), None);
724 assert_eq!(TypedArray::get(arr, 100), None);
725 assert_eq!(TypedArray::get(arr, u32::MAX), None);
726
727 TypedArray::push(arr, 1.0);
728 assert_eq!(TypedArray::get(arr, 0), Some(1.0));
729 assert_eq!(TypedArray::get(arr, 1), None);
730
731 TypedArray::drop_array(arr);
732 }
733 }
734
735 #[test]
736 fn test_refcount_with_typed_array() {
737 use crate::v2::refcount::{v2_get_refcount, v2_retain, v2_release};
738
739 let arr = TypedArray::<f64>::from_slice(&[1.0, 2.0]);
740 unsafe {
741 let header_ptr = arr as *const HeapHeader;
742
743 assert_eq!(v2_get_refcount(header_ptr), 1);
744
745 v2_retain(header_ptr);
746 assert_eq!(v2_get_refcount(header_ptr), 2);
747
748 assert!(!v2_release(header_ptr)); assert_eq!(v2_get_refcount(header_ptr), 1);
750
751 TypedArray::drop_array(arr);
753 }
754 }
755
756 #[test]
762 fn test_drop_array_heap_string_obj() {
763 use crate::v2::string_obj::StringObj;
764 unsafe {
765 let arr: *mut TypedArray<*const StringObj> = TypedArray::with_capacity(4);
767 let s1 = StringObj::new("hello");
769 let s2 = StringObj::new("world");
770 let s3 = StringObj::new("!");
771 TypedArray::push(arr, s1 as *const StringObj);
772 TypedArray::push(arr, s2 as *const StringObj);
773 TypedArray::push(arr, s3 as *const StringObj);
774 assert_eq!(TypedArray::len(arr), 3);
775 TypedArray::<*const StringObj>::drop_array_heap(arr);
778 }
779 }
780
781 #[test]
782 fn test_drop_array_heap_decimal_obj() {
783 use crate::v2::decimal_obj::DecimalObj;
784 use rust_decimal::Decimal;
785 use rust_decimal::prelude::FromPrimitive;
786 unsafe {
787 let arr: *mut TypedArray<*const DecimalObj> = TypedArray::with_capacity(4);
788 let d1 = DecimalObj::new(Decimal::from_f64(1.5).unwrap());
789 let d2 = DecimalObj::new(Decimal::from_f64(2.5).unwrap());
790 let d3 = DecimalObj::new(Decimal::ZERO);
791 TypedArray::push(arr, d1 as *const DecimalObj);
792 TypedArray::push(arr, d2 as *const DecimalObj);
793 TypedArray::push(arr, d3 as *const DecimalObj);
794 assert_eq!(TypedArray::len(arr), 3);
795 TypedArray::<*const DecimalObj>::drop_array_heap(arr);
796 }
797 }
798
799 #[test]
800 fn test_drop_array_heap_empty() {
801 use crate::v2::string_obj::StringObj;
802 unsafe {
803 let arr: *mut TypedArray<*const StringObj> = TypedArray::new();
805 TypedArray::<*const StringObj>::drop_array_heap(arr);
806 }
807 }
808
809 #[test]
814 fn test_size_of_typed_array_f32_char() {
815 assert_eq!(std::mem::size_of::<TypedArray<f32>>(), 24);
816 assert_eq!(std::mem::size_of::<TypedArray<char>>(), 24);
817 }
818
819 #[test]
820 fn test_push_and_get_f32() {
821 let arr = TypedArray::<f32>::new();
822 unsafe {
823 TypedArray::push(arr, 1.5_f32);
824 TypedArray::push(arr, 2.25_f32);
825 TypedArray::push(arr, std::f32::consts::PI);
826 assert_eq!(TypedArray::len(arr), 3);
827 assert_eq!(TypedArray::get(arr, 0), Some(1.5_f32));
828 assert_eq!(TypedArray::get(arr, 1), Some(2.25_f32));
829 assert_eq!(TypedArray::get(arr, 2), Some(std::f32::consts::PI));
830 assert_eq!(TypedArray::get(arr, 3), None);
831 TypedArray::drop_array(arr);
832 }
833 }
834
835 #[test]
836 fn test_push_and_get_char() {
837 let arr = TypedArray::<char>::new();
838 unsafe {
839 TypedArray::push(arr, 'a');
840 TypedArray::push(arr, '☃');
841 TypedArray::push(arr, '👋');
842 assert_eq!(TypedArray::len(arr), 3);
843 assert_eq!(TypedArray::get(arr, 0), Some('a'));
844 assert_eq!(TypedArray::get(arr, 1), Some('☃'));
845 assert_eq!(TypedArray::get(arr, 2), Some('👋'));
846 assert_eq!(TypedArray::get(arr, 3), None);
847 TypedArray::drop_array(arr);
848 }
849 }
850
851 #[test]
852 fn test_from_slice_f32() {
853 let data: [f32; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];
854 let arr = TypedArray::from_slice(&data);
855 unsafe {
856 assert_eq!(TypedArray::len(arr), 5);
857 for (i, &expected) in data.iter().enumerate() {
858 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
859 }
860 TypedArray::drop_array(arr);
861 }
862 }
863
864 #[test]
865 fn test_from_slice_char() {
866 let data = ['h', 'i', '!'];
867 let arr = TypedArray::from_slice(&data);
868 unsafe {
869 assert_eq!(TypedArray::len(arr), 3);
870 for (i, &expected) in data.iter().enumerate() {
871 assert_eq!(TypedArray::get(arr, i as u32), Some(expected));
872 }
873 TypedArray::drop_array(arr);
874 }
875 }
876
877 #[test]
878 fn test_drop_array_heap_with_held_share() {
879 use crate::v2::refcount::{v2_get_refcount, v2_retain};
880 use crate::v2::string_obj::StringObj;
881 unsafe {
882 let arr: *mut TypedArray<*const StringObj> = TypedArray::with_capacity(2);
885 let s = StringObj::new("shared");
886 v2_retain(&(*s).header); TypedArray::push(arr, s as *const StringObj);
888
889 TypedArray::<*const StringObj>::drop_array_heap(arr);
890
891 assert_eq!(v2_get_refcount(&(*s).header), 1);
893 assert_eq!(StringObj::as_str(s), "shared");
894 StringObj::drop(s);
896 }
897 }
898}