1use crate::value_word::ValueWord;
24use std::alloc::{self, Layout};
25use std::slice;
26
27#[repr(C)]
32pub struct ShapeArray {
33 data: *mut ValueWord,
35 len: u64,
37 cap: u64,
39}
40
41unsafe impl Send for ShapeArray {}
43unsafe impl Sync for ShapeArray {}
44
45const _: () = {
47 assert!(std::mem::size_of::<ShapeArray>() == 24);
48 assert!(std::mem::size_of::<ValueWord>() == 8);
49};
50
51impl ShapeArray {
53 pub const OFFSET_DATA: usize = 0;
55 pub const OFFSET_LEN: usize = 8;
57 pub const OFFSET_CAP: usize = 16;
59}
60
61impl ShapeArray {
62 #[inline]
64 pub fn new() -> Self {
65 Self {
66 data: std::ptr::null_mut(),
67 len: 0,
68 cap: 0,
69 }
70 }
71
72 pub fn with_capacity(cap: usize) -> Self {
74 if cap == 0 {
75 return Self::new();
76 }
77 let layout = Layout::array::<ValueWord>(cap).unwrap();
78 let data = unsafe { alloc::alloc(layout) as *mut ValueWord };
79 if data.is_null() {
80 alloc::handle_alloc_error(layout);
81 }
82 Self {
83 data,
84 len: 0,
85 cap: cap as u64,
86 }
87 }
88
89 pub fn from_iter(iter: impl IntoIterator<Item = ValueWord>) -> Self {
91 let vec: Vec<ValueWord> = iter.into_iter().collect();
92 Self::from_vec(vec)
93 }
94
95 pub fn from_vec(vec: Vec<ValueWord>) -> Self {
97 if vec.is_empty() {
98 return Self::new();
99 }
100 let len = vec.len() as u64;
101 let cap = vec.capacity() as u64;
102 let mut vec = std::mem::ManuallyDrop::new(vec);
103 let data = vec.as_mut_ptr();
104 Self { data, len, cap }
105 }
106
107 pub fn from_slice(elements: &[ValueWord]) -> Self {
109 if elements.is_empty() {
110 return Self::new();
111 }
112 let cap = elements.len();
113 let layout = Layout::array::<ValueWord>(cap).unwrap();
114 let data = unsafe { alloc::alloc(layout) as *mut ValueWord };
115 if data.is_null() {
116 alloc::handle_alloc_error(layout);
117 }
118 for (i, elem) in elements.iter().enumerate() {
120 unsafe {
121 std::ptr::write(data.add(i), elem.clone());
122 }
123 }
124 Self {
125 data,
126 len: elements.len() as u64,
127 cap: cap as u64,
128 }
129 }
130
131 pub unsafe fn from_raw_u64_slice(elements: &[u64]) -> Self {
138 if elements.is_empty() {
139 return Self::new();
140 }
141 let cap = elements.len();
142 let layout = Layout::array::<ValueWord>(cap).unwrap();
143 let data = unsafe { alloc::alloc(layout) as *mut ValueWord };
145 if data.is_null() {
146 alloc::handle_alloc_error(layout);
147 }
148 unsafe {
151 std::ptr::copy_nonoverlapping(
152 elements.as_ptr() as *const ValueWord,
153 data,
154 elements.len(),
155 );
156 }
157 Self {
158 data,
159 len: elements.len() as u64,
160 cap: cap as u64,
161 }
162 }
163
164 #[inline]
166 pub fn len(&self) -> usize {
167 self.len as usize
168 }
169
170 #[inline]
172 pub fn is_empty(&self) -> bool {
173 self.len == 0
174 }
175
176 #[inline]
178 pub fn capacity(&self) -> usize {
179 self.cap as usize
180 }
181
182 #[inline]
184 pub fn as_slice(&self) -> &[ValueWord] {
185 if self.data.is_null() || self.len == 0 {
186 return &[];
187 }
188 unsafe { slice::from_raw_parts(self.data, self.len as usize) }
189 }
190
191 #[inline]
193 pub fn as_mut_slice(&mut self) -> &mut [ValueWord] {
194 if self.data.is_null() || self.len == 0 {
195 return &mut [];
196 }
197 unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) }
198 }
199
200 #[inline]
202 pub fn as_raw_u64_slice(&self) -> &[u64] {
203 if self.data.is_null() || self.len == 0 {
204 return &[];
205 }
206 unsafe { slice::from_raw_parts(self.data as *const u64, self.len as usize) }
208 }
209
210 #[inline]
212 pub fn as_ptr(&self) -> *const ValueWord {
213 self.data
214 }
215
216 #[inline]
218 pub fn as_mut_ptr(&mut self) -> *mut ValueWord {
219 self.data
220 }
221
222 #[inline]
224 pub fn get(&self, index: usize) -> Option<&ValueWord> {
225 if index < self.len as usize {
226 unsafe { Some(&*self.data.add(index)) }
227 } else {
228 None
229 }
230 }
231
232 pub fn push(&mut self, value: ValueWord) {
234 if self.len == self.cap {
235 self.grow();
236 }
237 unsafe {
238 std::ptr::write(self.data.add(self.len as usize), value);
239 }
240 self.len += 1;
241 }
242
243 pub fn pop(&mut self) -> Option<ValueWord> {
245 if self.len == 0 {
246 return None;
247 }
248 self.len -= 1;
249 unsafe { Some(std::ptr::read(self.data.add(self.len as usize))) }
250 }
251
252 #[inline]
254 pub fn iter(&self) -> slice::Iter<'_, ValueWord> {
255 self.as_slice().iter()
256 }
257
258 #[inline]
260 pub fn first(&self) -> Option<&ValueWord> {
261 if self.len > 0 {
262 unsafe { Some(&*self.data) }
263 } else {
264 None
265 }
266 }
267
268 #[inline]
270 pub fn last(&self) -> Option<&ValueWord> {
271 if self.len > 0 {
272 unsafe { Some(&*self.data.add(self.len as usize - 1)) }
273 } else {
274 None
275 }
276 }
277
278 pub fn to_vec(&self) -> Vec<ValueWord> {
280 self.as_slice().to_vec()
281 }
282
283 pub fn into_vec(self) -> Vec<ValueWord> {
285 if self.data.is_null() || self.len == 0 {
286 std::mem::forget(self);
287 return Vec::new();
288 }
289 let vec = unsafe { Vec::from_raw_parts(self.data, self.len as usize, self.cap as usize) };
290 std::mem::forget(self); vec
292 }
293
294 fn grow(&mut self) {
296 let new_cap = if self.cap == 0 { 4 } else { self.cap * 2 };
297 let new_layout = Layout::array::<ValueWord>(new_cap as usize).unwrap();
298
299 let new_data = if self.data.is_null() {
300 unsafe { alloc::alloc(new_layout) as *mut ValueWord }
301 } else {
302 let old_layout = Layout::array::<ValueWord>(self.cap as usize).unwrap();
303 unsafe {
304 alloc::realloc(self.data as *mut u8, old_layout, new_layout.size())
305 as *mut ValueWord
306 }
307 };
308
309 if new_data.is_null() {
310 alloc::handle_alloc_error(new_layout);
311 }
312 self.data = new_data;
313 self.cap = new_cap;
314 }
315}
316
317impl Drop for ShapeArray {
318 fn drop(&mut self) {
319 if !self.data.is_null() && self.cap > 0 {
320 for i in 0..self.len as usize {
322 unsafe {
323 std::ptr::drop_in_place(self.data.add(i));
324 }
325 }
326 let layout = Layout::array::<ValueWord>(self.cap as usize).unwrap();
327 unsafe {
328 alloc::dealloc(self.data as *mut u8, layout);
329 }
330 }
331 }
332}
333
334impl Clone for ShapeArray {
335 fn clone(&self) -> Self {
336 Self::from_slice(self.as_slice())
337 }
338}
339
340impl Default for ShapeArray {
341 fn default() -> Self {
342 Self::new()
343 }
344}
345
346impl std::fmt::Debug for ShapeArray {
347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348 f.debug_struct("ShapeArray")
349 .field("len", &self.len)
350 .field("cap", &self.cap)
351 .finish()
352 }
353}
354
355impl std::ops::Index<usize> for ShapeArray {
356 type Output = ValueWord;
357
358 #[inline]
359 fn index(&self, index: usize) -> &ValueWord {
360 assert!(
361 index < self.len as usize,
362 "ShapeArray index out of bounds: {} >= {}",
363 index,
364 self.len
365 );
366 unsafe { &*self.data.add(index) }
367 }
368}
369
370impl std::ops::IndexMut<usize> for ShapeArray {
371 #[inline]
372 fn index_mut(&mut self, index: usize) -> &mut ValueWord {
373 assert!(
374 index < self.len as usize,
375 "ShapeArray index out of bounds: {} >= {}",
376 index,
377 self.len
378 );
379 unsafe { &mut *self.data.add(index) }
380 }
381}
382
383impl<'a> IntoIterator for &'a ShapeArray {
384 type Item = &'a ValueWord;
385 type IntoIter = slice::Iter<'a, ValueWord>;
386
387 fn into_iter(self) -> Self::IntoIter {
388 self.iter()
389 }
390}
391
392impl PartialEq for ShapeArray {
393 fn eq(&self, other: &Self) -> bool {
394 if self.len != other.len {
395 return false;
396 }
397 self.as_raw_u64_slice() == other.as_raw_u64_slice()
399 }
400}
401
402impl From<Vec<ValueWord>> for ShapeArray {
403 fn from(vec: Vec<ValueWord>) -> Self {
404 Self::from_vec(vec)
405 }
406}
407
408impl From<ShapeArray> for Vec<ValueWord> {
409 fn from(arr: ShapeArray) -> Self {
410 arr.into_vec()
411 }
412}
413
414impl From<std::sync::Arc<Vec<ValueWord>>> for ShapeArray {
415 fn from(arc: std::sync::Arc<Vec<ValueWord>>) -> Self {
418 Self::from_slice(&arc)
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425
426 #[test]
427 fn test_repr_c_layout() {
428 assert_eq!(
429 std::mem::offset_of!(ShapeArray, data),
430 ShapeArray::OFFSET_DATA
431 );
432 assert_eq!(
433 std::mem::offset_of!(ShapeArray, len),
434 ShapeArray::OFFSET_LEN
435 );
436 assert_eq!(
437 std::mem::offset_of!(ShapeArray, cap),
438 ShapeArray::OFFSET_CAP
439 );
440 assert_eq!(std::mem::size_of::<ShapeArray>(), 24);
441 }
442
443 #[test]
444 fn test_new_empty() {
445 let arr = ShapeArray::new();
446 assert_eq!(arr.len(), 0);
447 assert!(arr.is_empty());
448 assert_eq!(arr.as_slice().len(), 0);
449 }
450
451 #[test]
452 fn test_push_pop() {
453 let mut arr = ShapeArray::new();
454 arr.push(ValueWord::from_f64(1.0));
455 arr.push(ValueWord::from_i64(2));
456 arr.push(ValueWord::from_bool(true));
457 assert_eq!(arr.len(), 3);
458
459 let v = arr.pop().unwrap();
460 assert_eq!(v.as_bool(), Some(true));
461 assert_eq!(arr.len(), 2);
462
463 let v = arr.pop().unwrap();
464 assert_eq!(v.as_i64(), Some(2));
465
466 let v = arr.pop().unwrap();
467 assert_eq!(v.as_f64(), Some(1.0));
468
469 assert!(arr.pop().is_none());
470 }
471
472 #[test]
473 fn test_from_vec() {
474 let vec = vec![ValueWord::from_f64(10.0), ValueWord::from_f64(20.0)];
475 let arr = ShapeArray::from_vec(vec);
476 assert_eq!(arr.len(), 2);
477 assert_eq!(arr[0].as_f64(), Some(10.0));
478 assert_eq!(arr[1].as_f64(), Some(20.0));
479 }
480
481 #[test]
482 fn test_from_slice() {
483 let elements = [
484 ValueWord::from_i64(1),
485 ValueWord::from_i64(2),
486 ValueWord::from_i64(3),
487 ];
488 let arr = ShapeArray::from_slice(&elements);
489 assert_eq!(arr.len(), 3);
490 assert_eq!(arr[0].as_i64(), Some(1));
491 assert_eq!(arr[2].as_i64(), Some(3));
492 }
493
494 #[test]
495 fn test_clone() {
496 let mut arr = ShapeArray::new();
497 arr.push(ValueWord::from_string(std::sync::Arc::new(
498 "hello".to_string(),
499 )));
500 arr.push(ValueWord::from_f64(42.0));
501 let cloned = arr.clone();
502 assert_eq!(cloned.len(), 2);
503 assert_eq!(cloned[0].as_str(), Some("hello"));
504 assert_eq!(cloned[1].as_f64(), Some(42.0));
505 }
506
507 #[test]
508 fn test_into_vec() {
509 let mut arr = ShapeArray::new();
510 arr.push(ValueWord::from_i64(5));
511 arr.push(ValueWord::from_i64(10));
512 let vec = arr.into_vec();
513 assert_eq!(vec.len(), 2);
514 assert_eq!(vec[0].as_i64(), Some(5));
515 assert_eq!(vec[1].as_i64(), Some(10));
516 }
517
518 #[test]
519 fn test_growth() {
520 let mut arr = ShapeArray::new();
521 for i in 0..100 {
522 arr.push(ValueWord::from_i64(i));
523 }
524 assert_eq!(arr.len(), 100);
525 for i in 0..100 {
526 assert_eq!(arr[i].as_i64(), Some(i as i64));
527 }
528 }
529
530 #[test]
531 fn test_index_access() {
532 let mut arr = ShapeArray::from_vec(vec![
533 ValueWord::from_f64(10.0),
534 ValueWord::from_f64(20.0),
535 ValueWord::from_f64(30.0),
536 ]);
537 assert_eq!(arr[0].as_f64(), Some(10.0));
538 assert_eq!(arr[1].as_f64(), Some(20.0));
539 arr[1] = ValueWord::from_f64(99.0);
540 assert_eq!(arr[1].as_f64(), Some(99.0));
541 }
542
543 #[test]
544 fn test_with_capacity() {
545 let mut arr = ShapeArray::with_capacity(10);
546 assert_eq!(arr.len(), 0);
547 assert!(arr.is_empty());
548 assert!(arr.capacity() >= 10);
549 arr.push(ValueWord::from_i64(42));
550 assert_eq!(arr.len(), 1);
551 assert_eq!(arr[0].as_i64(), Some(42));
552 }
553
554 #[test]
555 fn test_first_last() {
556 let arr = ShapeArray::from_vec(vec![
557 ValueWord::from_i64(10),
558 ValueWord::from_i64(20),
559 ValueWord::from_i64(30),
560 ]);
561 assert_eq!(arr.first().unwrap().as_i64(), Some(10));
562 assert_eq!(arr.last().unwrap().as_i64(), Some(30));
563
564 let empty = ShapeArray::new();
565 assert!(empty.first().is_none());
566 assert!(empty.last().is_none());
567 }
568
569 #[test]
570 fn test_iter() {
571 let arr = ShapeArray::from_vec(vec![
572 ValueWord::from_i64(1),
573 ValueWord::from_i64(2),
574 ValueWord::from_i64(3),
575 ]);
576 let sum: i64 = arr.iter().map(|nb| nb.as_i64().unwrap_or(0)).sum();
577 assert_eq!(sum, 6);
578 }
579
580 #[test]
581 fn test_raw_u64_interop() {
582 let values = [ValueWord::from_f64(1.0), ValueWord::from_f64(2.0)];
583 let arr = ShapeArray::from_slice(&values);
584 let raw = arr.as_raw_u64_slice();
585 assert_eq!(raw.len(), 2);
586 assert_eq!(raw[0], 1.0f64.to_bits());
588 assert_eq!(raw[1], 2.0f64.to_bits());
589 }
590
591 #[test]
592 fn test_heap_values_cloned_correctly() {
593 use std::sync::Arc;
594 let s = Arc::new("test".to_string());
595 let nb = ValueWord::from_string(s.clone());
596
597 let mut arr = ShapeArray::new();
598 arr.push(nb.clone());
599 arr.push(nb.clone());
600
601 let arr2 = arr.clone();
603 assert_eq!(arr2.len(), 2);
604 assert_eq!(arr2[0].as_str(), Some("test"));
605
606 drop(arr);
608 drop(arr2);
609
610 assert_eq!(&*s, "test");
612 }
613
614 #[test]
615 fn test_empty_into_vec() {
616 let arr = ShapeArray::new();
617 let vec = arr.into_vec();
618 assert!(vec.is_empty());
619 }
620}