Skip to main content

primitives/types/heap_array/
array.rs

1use std::{
2    fmt::{Debug, Display},
3    marker::PhantomData,
4    mem::{ManuallyDrop, MaybeUninit},
5    ops::{Add, Mul, Sub},
6    sync::Arc,
7    vec,
8};
9
10use bytemuck::{box_bytes_of, from_box_bytes, BoxBytes, Pod};
11use derive_more::derive::{AsMut, AsRef, Deref, DerefMut, IntoIterator};
12use hybrid_array::{Array, ArraySize};
13use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
14use serde::{Deserialize, Serialize};
15use typenum::{Diff, Prod, Sum, Unsigned, U1, U2, U3, U5};
16use wincode::{
17    io::{Reader, Writer},
18    ReadResult,
19    SchemaRead,
20    SchemaWrite,
21    TypeMeta,
22    WriteResult,
23};
24
25use crate::{errors::PrimitiveError, types::Positive};
26
27/// An array on the heap that encodes its length in the type system.
28#[derive(Deref, DerefMut, Clone, IntoIterator, AsRef, AsMut, Eq)]
29#[into_iterator(owned, ref, ref_mut)]
30pub struct HeapArray<T: Sized, M: Positive> {
31    #[deref]
32    #[deref_mut]
33    #[as_ref(forward)]
34    #[as_mut(forward)]
35    pub(super) data: Box<[T]>,
36    #[into_iterator(ignore)]
37    // `fn() -> M` is used instead of `M` so `HeapArray<T, M>` doesn't need `M` to implement `Send
38    // + Sync` to be `Send + Sync` itself. This would be the case if `M` was used directly.
39    pub(super) _len: PhantomData<fn() -> M>,
40}
41
42impl<T: Sized, M: Positive> HeapArray<T, M> {
43    pub(super) fn new(data: Box<[T]>) -> Self {
44        Self {
45            data,
46            _len: PhantomData,
47        }
48    }
49}
50
51impl<T: Sized, M: Positive> HeapArray<T, M> {
52    /// Zero-copy cast from a `#[repr(transparent)]` wrapper to its inner type.
53    pub fn peel_transparent<U>(self) -> HeapArray<U, M>
54    where
55        T: bytemuck::TransparentWrapper<U>,
56    {
57        use bytemuck::allocation::TransparentWrapperAlloc;
58        HeapArray::new(T::peel_vec(self.data.into_vec()).into_boxed_slice())
59    }
60
61    /// Zero-copy cast from a type to its `#[repr(transparent)]` wrapper.
62    pub fn wrap_transparent<W>(self) -> HeapArray<W, M>
63    where
64        W: bytemuck::TransparentWrapper<T>,
65    {
66        use bytemuck::allocation::TransparentWrapperAlloc;
67        HeapArray::new(W::wrap_vec(self.data.into_vec()).into_boxed_slice())
68    }
69}
70
71// bytemuck::BoxBytes transformation for copy-less casting
72impl<T: Pod, M: Positive> HeapArray<T, M> {
73    pub fn into_box_bytes(self) -> BoxBytes {
74        box_bytes_of(self.data)
75    }
76
77    pub fn from_box_bytes(buf: BoxBytes) -> Self {
78        Self {
79            data: from_box_bytes(buf),
80            _len: PhantomData,
81        }
82    }
83}
84
85impl<T: Sized, M: Positive> HeapArray<T, M> {
86    pub fn map<F, U>(self, f: F) -> HeapArray<U, M>
87    where
88        F: FnMut(T) -> U,
89    {
90        self.into_iter().map(f).collect()
91    }
92
93    /// Destructure into a fixed-size array `[T; K]`.
94    ///
95    /// `K` is inferred from the destructuring pattern at the call site
96    /// (e.g. `let [a, b, c] = ha.into_array();` fixes `K = 3`). A mismatch
97    /// between `K` and `M::USIZE` is a compile-time error.
98    pub fn into_array<const K: usize>(self) -> [T; K] {
99        const {
100            assert!(
101                M::USIZE == K,
102                "HeapArray length does not match destructured array length",
103            );
104        }
105        // SAFETY: the const assert above proves `self.data.len() == M::USIZE == K`,
106        // and `Box<[T]>` with length `K` has the same layout as `Box<[T; K]>`.
107        let raw: *mut [T] = Box::into_raw(self.data);
108        unsafe { *Box::from_raw(raw.cast::<[T; K]>()) }
109    }
110}
111
112impl<T: Sized + Default, M: Positive> HeapArray<T, M> {
113    pub fn from_single_value(val: T) -> Self {
114        Self {
115            data: vec![val].into_boxed_slice(),
116            _len: PhantomData,
117        }
118    }
119}
120
121impl<T: Sized + Default, M: Positive> Default for HeapArray<T, M> {
122    fn default() -> Self {
123        Self {
124            data: (0..M::USIZE).map(|_| T::default()).collect(),
125            _len: PhantomData,
126        }
127    }
128}
129
130impl<T: Sized + Debug, M: Positive> Debug for HeapArray<T, M> {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        f.debug_struct(format!("HeapArray<{}>", M::USIZE).as_str())
133            .field("data", &self.data)
134            .finish()
135    }
136}
137
138impl<T: Sized + Serialize, M: Positive> Serialize for HeapArray<T, M> {
139    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
140        use serde::ser::SerializeTuple;
141        let mut tuple = serializer.serialize_tuple(M::USIZE)?;
142        for element in self.data.iter() {
143            tuple.serialize_element(element)?;
144        }
145        tuple.end()
146    }
147}
148
149impl<'de, T: Sized + Deserialize<'de>, M: Positive> Deserialize<'de> for HeapArray<T, M> {
150    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
151        struct HeapArrayVisitor<T, M: Positive> {
152            _phantom: PhantomData<(T, M)>,
153        }
154
155        impl<'de, T: Deserialize<'de>, M: Positive> serde::de::Visitor<'de> for HeapArrayVisitor<T, M> {
156            type Value = HeapArray<T, M>;
157
158            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
159                write!(formatter, "a tuple of {} elements", M::USIZE)
160            }
161
162            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
163            where
164                A: serde::de::SeqAccess<'de>,
165            {
166                let mut data = Vec::with_capacity(M::USIZE);
167                for i in 0..M::USIZE {
168                    let element = seq
169                        .next_element()?
170                        .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
171                    data.push(element);
172                }
173
174                Ok(HeapArray {
175                    data: data.into_boxed_slice(),
176                    _len: PhantomData,
177                })
178            }
179        }
180
181        deserializer.deserialize_tuple(
182            M::USIZE,
183            HeapArrayVisitor {
184                _phantom: PhantomData,
185            },
186        )
187    }
188}
189
190impl<T: Sized + SchemaWrite<Src = T>, M: Positive> SchemaWrite for HeapArray<T, M> {
191    type Src = HeapArray<T, M>;
192
193    const TYPE_META: wincode::TypeMeta = match <T as SchemaWrite>::TYPE_META {
194        TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
195            size: size * M::USIZE,
196            zero_copy,
197        },
198        TypeMeta::Dynamic => TypeMeta::Dynamic,
199    };
200
201    #[inline]
202    fn size_of(src: &Self::Src) -> WriteResult<usize> {
203        if let TypeMeta::Static { size, .. } = <Self as SchemaWrite>::TYPE_META {
204            return Ok(size);
205        }
206
207        // Extremely unlikely a type-in-memory's size will overflow usize::MAX.
208        src.iter()
209            .map(T::size_of)
210            .try_fold(0usize, |acc, x| x.map(|x| acc + x))
211    }
212
213    #[inline]
214    fn write(writer: &mut impl Writer, src: &Self::Src) -> WriteResult<()> {
215        if let TypeMeta::Static {
216            size,
217            zero_copy: true,
218        } = <Self as SchemaWrite>::TYPE_META
219        {
220            // SAFETY: `size` is the size of the encoded length. `writer.write(src)` will write
221            // `size` bytes, fully initializing the trusted window.
222            let writer = &mut unsafe { writer.as_trusted_for(size) }?;
223            // SAFETY: `T::Src` is zero-copy eligible (no invalid bit patterns, no layout
224            // requirements, no endianness checks, etc.).
225            unsafe { writer.write_slice_t(&src.data)? };
226            writer.finish()?;
227        } else if let TypeMeta::Static { size, .. } = <Self as SchemaWrite>::TYPE_META {
228            #[allow(clippy::arithmetic_side_effects)]
229            // SAFETY: `size` is the size of the encoded length.
230            // M writes of `T::Src` will write `size` bytes,
231            // fully initializing the trusted window.
232            let mut writer = unsafe { writer.as_trusted_for(size) }?;
233            for item in src {
234                T::write(&mut writer, item)?;
235            }
236            writer.finish()?;
237        } else {
238            for item in src {
239                T::write(writer, item)?;
240            }
241        }
242
243        Ok(())
244    }
245}
246
247pub(crate) struct SliceDropGuard<T> {
248    ptr: *mut MaybeUninit<T>,
249    initialized_len: usize,
250}
251
252impl<T> SliceDropGuard<T> {
253    pub(crate) fn new(ptr: *mut MaybeUninit<T>) -> Self {
254        Self {
255            ptr,
256            initialized_len: 0,
257        }
258    }
259
260    #[inline(always)]
261    #[allow(clippy::arithmetic_side_effects)]
262    pub(crate) fn inc_len(&mut self) {
263        self.initialized_len += 1;
264    }
265}
266
267impl<T> Drop for SliceDropGuard<T> {
268    #[inline(always)]
269    fn drop(&mut self) {
270        unsafe {
271            std::ptr::drop_in_place(std::ptr::slice_from_raw_parts_mut(
272                self.ptr.cast::<T>(),
273                self.initialized_len,
274            ));
275        }
276    }
277}
278
279impl<'de, T: Sized + SchemaRead<'de, Dst = T>, M: Positive> SchemaRead<'de> for HeapArray<T, M> {
280    type Dst = HeapArray<T::Dst, M>;
281
282    const TYPE_META: TypeMeta = const {
283        match T::TYPE_META {
284            TypeMeta::Static { size, zero_copy } => TypeMeta::Static {
285                size: M::USIZE * size,
286                zero_copy,
287            },
288            TypeMeta::Dynamic => TypeMeta::Dynamic,
289        }
290    };
291
292    #[inline]
293    fn read(reader: &mut impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
294        /// Drop guard for `TypeMeta::Static { zero_copy: true }` types.
295        ///
296        /// In this case we do not need to drop items individually, as
297        /// the container will be initialized by a single memcpy.
298        struct DropGuardRawCopy<T>(*mut [MaybeUninit<T>]);
299        impl<T> Drop for DropGuardRawCopy<T> {
300            #[inline]
301            fn drop(&mut self) {
302                let container = unsafe { Box::from_raw(self.0) };
303                drop(container);
304            }
305        }
306        /// Drop guard for `TypeMeta::Static { zero_copy: false } | TypeMeta::Dynamic` types.
307        ///
308        /// In this case we need to drop items individually, as
309        /// the container will be initialized by a series of reads.
310        struct DropGuardElemCopy<T> {
311            inner: ManuallyDrop<SliceDropGuard<T>>,
312            fat: *mut [MaybeUninit<T>],
313        }
314        impl<T> DropGuardElemCopy<T> {
315            #[inline(always)]
316            fn new(fat: *mut [MaybeUninit<T>], raw: *mut MaybeUninit<T>) -> Self {
317                Self {
318                    inner: ManuallyDrop::new(SliceDropGuard::new(raw)),
319                    fat,
320                }
321            }
322        }
323        impl<T> Drop for DropGuardElemCopy<T> {
324            #[inline]
325            fn drop(&mut self) {
326                unsafe {
327                    ManuallyDrop::drop(&mut self.inner);
328                }
329                let container = unsafe { Box::from_raw(self.fat) };
330                drop(container);
331            }
332        }
333        let mem = Box::<[T::Dst]>::new_uninit_slice(M::USIZE);
334        let fat = Box::into_raw(mem);
335        match T::TYPE_META {
336            TypeMeta::Static {
337                zero_copy: true, ..
338            } => {
339                let guard = DropGuardRawCopy(fat);
340                let dst = unsafe { &mut *fat };
341                unsafe { reader.copy_into_slice_t(dst)? };
342                std::mem::forget(guard);
343            }
344            TypeMeta::Static {
345                size,
346                zero_copy: false,
347            } => {
348                let raw_base = unsafe { (*fat).as_mut_ptr() };
349                let mut guard: DropGuardElemCopy<T::Dst> = DropGuardElemCopy::new(fat, raw_base);
350                #[allow(clippy::arithmetic_side_effects)]
351                let reader = &mut unsafe { reader.as_trusted_for(size * M::USIZE) }?;
352                for i in 0..M::USIZE {
353                    let slot = unsafe { &mut *raw_base.add(i) };
354                    T::read(reader, slot)?;
355                    guard.inner.inc_len();
356                }
357                std::mem::forget(guard);
358            }
359            TypeMeta::Dynamic => {
360                let raw_base = unsafe { (*fat).as_mut_ptr() };
361                let mut guard: DropGuardElemCopy<T::Dst> = DropGuardElemCopy::new(fat, raw_base);
362                for i in 0..M::USIZE {
363                    let slot = unsafe { &mut *raw_base.add(i) };
364                    T::read(reader, slot)?;
365                    guard.inner.inc_len();
366                }
367                std::mem::forget(guard);
368            }
369        }
370        let container = unsafe { Box::from_raw(fat) };
371        let container = unsafe { container.assume_init().try_into().unwrap() };
372        dst.write(container);
373        Ok(())
374    }
375}
376
377impl<T: Sized, M: Positive> FromIterator<T> for HeapArray<T, M> {
378    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
379        let data = iter.into_iter().collect::<Box<_>>();
380        assert_eq!(data.len(), M::USIZE,);
381        Self {
382            data,
383            _len: PhantomData,
384        }
385    }
386}
387
388impl<T: Sized + Send, M: Positive> IntoParallelIterator for HeapArray<T, M> {
389    type Item = T;
390    type Iter = rayon::vec::IntoIter<T>;
391
392    fn into_par_iter(self) -> Self::Iter {
393        self.data.into_par_iter()
394    }
395}
396
397impl<T: Sized + Send, M: Positive> FromParallelIterator<T> for HeapArray<T, M> {
398    fn from_par_iter<I: IntoParallelIterator<Item = T>>(par_iter: I) -> Self {
399        let data: Box<[T]> = par_iter.into_par_iter().collect::<Vec<T>>().into();
400        assert_eq!(data.len(), M::USIZE);
401        Self {
402            data,
403            _len: PhantomData,
404        }
405    }
406}
407
408// -----------------------
409// |   Split and Merge   |
410// -----------------------
411
412impl<T: Sized + Copy, M: Positive> HeapArray<T, M> {
413    pub fn split<M1, M2>(&self) -> (HeapArray<T, M1>, HeapArray<T, M2>)
414    where
415        M1: Positive,
416        M2: Positive + Add<M1, Output = M>,
417    {
418        let (m1, m2) = self.split_at(M1::USIZE);
419        (
420            HeapArray::<T, M1> {
421                data: m1.into(),
422                _len: PhantomData,
423            },
424            HeapArray::<T, M2> {
425                data: m2.into(),
426                _len: PhantomData,
427            },
428        )
429    }
430
431    pub fn split_last_pos<M1>(self) -> (HeapArray<T, M1>, T)
432    where
433        M1: Positive + Add<typenum::B1, Output = M>,
434    {
435        let Self { data, .. } = self;
436        let mut data = data.into_vec();
437        let last = data.pop().expect("HeapArray is empty");
438        (
439            HeapArray::<T, M1> {
440                data: data.into_boxed_slice(),
441                _len: PhantomData,
442            },
443            last,
444        )
445    }
446
447    pub fn split_halves<MDiv2>(&self) -> (HeapArray<T, MDiv2>, HeapArray<T, MDiv2>)
448    where
449        MDiv2: Positive + Mul<U2, Output = M>,
450    {
451        let (m1, m2) = self.split_at(MDiv2::USIZE);
452        (
453            HeapArray::<T, MDiv2> {
454                data: m1.into(),
455                _len: PhantomData,
456            },
457            HeapArray::<T, MDiv2> {
458                data: m2.into(),
459                _len: PhantomData,
460            },
461        )
462    }
463
464    pub fn merge_halves(this: Self, other: Self) -> HeapArray<T, Prod<M, U2>>
465    where
466        M: Mul<U2, Output: Positive>,
467    {
468        let mut vec = this.data.into_vec();
469        vec.extend(other.data.into_vec());
470        HeapArray::<T, Prod<M, U2>> {
471            data: vec.into_boxed_slice(),
472            _len: PhantomData,
473        }
474    }
475
476    pub fn split3<M1, M2, M3>(&self) -> (HeapArray<T, M1>, HeapArray<T, M2>, HeapArray<T, M3>)
477    where
478        M1: Positive,
479        M2: Positive + Add<M1>,
480        M3: Positive + Add<Sum<M2, M1>, Output = M>,
481    {
482        let (m1, m_rest) = self.split_at(M1::USIZE);
483        let (m2, m3) = m_rest.split_at(M2::USIZE);
484        (
485            HeapArray::<T, M1> {
486                data: m1.into(),
487                _len: PhantomData,
488            },
489            HeapArray::<T, M2> {
490                data: m2.into(),
491                _len: PhantomData,
492            },
493            HeapArray::<T, M3> {
494                data: m3.into(),
495                _len: PhantomData,
496            },
497        )
498    }
499
500    pub fn split_thirds<MDiv3>(
501        &self,
502    ) -> (
503        HeapArray<T, MDiv3>,
504        HeapArray<T, MDiv3>,
505        HeapArray<T, MDiv3>,
506    )
507    where
508        MDiv3: Positive + Mul<U3, Output = M>,
509    {
510        let (m1, m_rest) = self.split_at(MDiv3::USIZE);
511        let (m2, m3) = m_rest.split_at(MDiv3::USIZE);
512        (
513            HeapArray::<T, MDiv3> {
514                data: m1.into(),
515                _len: PhantomData,
516            },
517            HeapArray::<T, MDiv3> {
518                data: m2.into(),
519                _len: PhantomData,
520            },
521            HeapArray::<T, MDiv3> {
522                data: m3.into(),
523                _len: PhantomData,
524            },
525        )
526    }
527
528    pub fn merge_thirds(first: Self, second: Self, third: Self) -> HeapArray<T, Prod<M, U3>>
529    where
530        M: Mul<U3, Output: Positive>,
531    {
532        let mut vec = first.data.into_vec();
533        vec.extend(second.data.into_vec());
534        vec.extend(third.data.into_vec());
535        HeapArray::<T, Prod<M, U3>> {
536            data: vec.into_boxed_slice(),
537            _len: PhantomData,
538        }
539    }
540
541    pub fn merge_fifths(
542        first: Self,
543        second: Self,
544        third: Self,
545        fourth: Self,
546        fifth: Self,
547    ) -> HeapArray<T, Prod<M, U5>>
548    where
549        M: Mul<U5, Output: Positive>,
550    {
551        let mut vec = first.data.into_vec();
552        vec.reserve_exact(M::USIZE * 4);
553        vec.extend(second.data.into_vec());
554        vec.extend(third.data.into_vec());
555        vec.extend(fourth.data.into_vec());
556        vec.extend(fifth.data.into_vec());
557        HeapArray::<T, Prod<M, U5>> {
558            data: vec.into_boxed_slice(),
559            _len: PhantomData,
560        }
561    }
562}
563
564pub struct HeapArrayTuple<T1: Sized, T2: Sized, M: Positive>(
565    pub HeapArray<T1, M>,
566    pub HeapArray<T2, M>,
567);
568
569impl<T1: Sized, T2: Sized, M: Positive> FromIterator<(T1, T2)> for HeapArrayTuple<T1, T2, M> {
570    fn from_iter<I: IntoIterator<Item = (T1, T2)>>(iter: I) -> Self {
571        let (data1, data2): (Vec<_>, Vec<_>) = iter.into_iter().unzip();
572
573        assert_eq!(data1.len(), M::USIZE);
574        assert_eq!(data2.len(), M::USIZE);
575        HeapArrayTuple(
576            HeapArray::<T1, M> {
577                data: data1.into_boxed_slice(),
578                _len: PhantomData,
579            },
580            HeapArray::<T2, M> {
581                data: data2.into_boxed_slice(),
582                _len: PhantomData,
583            },
584        )
585    }
586}
587
588impl<T: Sized, M: Positive> TryFrom<Vec<T>> for HeapArray<T, M> {
589    type Error = PrimitiveError;
590
591    fn try_from(data: Vec<T>) -> Result<Self, PrimitiveError> {
592        if data.len() == M::USIZE {
593            Ok(Self {
594                data: data.into_boxed_slice(),
595                _len: PhantomData,
596            })
597        } else {
598            Err(PrimitiveError::InvalidSize(M::USIZE, data.len()))
599        }
600    }
601}
602
603impl<T: Sized, M: Positive> TryFrom<Box<[T]>> for HeapArray<T, M> {
604    type Error = PrimitiveError;
605
606    fn try_from(data: Box<[T]>) -> Result<Self, PrimitiveError> {
607        if data.len() == M::USIZE {
608            Ok(Self {
609                data,
610                _len: PhantomData,
611            })
612        } else {
613            Err(PrimitiveError::InvalidSize(M::USIZE, data.len()))
614        }
615    }
616}
617
618impl<T: Sized + Clone, M: Positive> TryFrom<Arc<[T]>> for HeapArray<T, M> {
619    type Error = PrimitiveError;
620
621    fn try_from(data: Arc<[T]>) -> Result<Self, PrimitiveError> {
622        if data.len() != M::USIZE {
623            return Err(PrimitiveError::InvalidSize(M::USIZE, data.len()));
624        }
625        Ok(Self {
626            data: data.to_vec().into_boxed_slice(),
627            _len: PhantomData,
628        })
629    }
630}
631
632impl<T: Sized> From<T> for HeapArray<T, U1> {
633    fn from(element: T) -> Self {
634        Self {
635            data: Box::new([element]),
636            _len: PhantomData,
637        }
638    }
639}
640
641impl<T: Sized, M: Positive> From<HeapArray<T, M>> for Vec<T> {
642    fn from(array: HeapArray<T, M>) -> Self {
643        array.data.into_vec()
644    }
645}
646
647impl<T: Sized + Clone, M: Positive + ArraySize> From<Array<T, M>> for HeapArray<T, M> {
648    fn from(array: Array<T, M>) -> Self {
649        Self {
650            data: array.to_vec().into_boxed_slice(),
651            _len: PhantomData,
652        }
653    }
654}
655
656impl<T: Sized, M: Positive> HeapArray<T, M> {
657    /// Take the first `N` elements and discard the rest. `N` may equal `M`
658    /// (no slack) or be strictly less.
659    pub fn truncate<N>(self) -> HeapArray<T, N>
660    where
661        N: Positive,
662        M: Sub<N, Output: Unsigned>,
663    {
664        let mut vec = self.data.into_vec();
665        vec.truncate(N::USIZE);
666        HeapArray {
667            data: vec.into_boxed_slice(),
668            _len: PhantomData,
669        }
670    }
671
672    pub fn split_last<N: Positive>(self) -> (HeapArray<T, Diff<M, N>>, HeapArray<T, N>)
673    where
674        M: Sub<N, Output: Positive>,
675    {
676        let mut vec = self.data.into_vec();
677        let last_n = vec.split_off(M::USIZE - N::USIZE);
678
679        (
680            HeapArray {
681                data: vec.into_boxed_slice(),
682                _len: PhantomData,
683            },
684            HeapArray {
685                data: last_n.into_boxed_slice(),
686                _len: PhantomData,
687            },
688        )
689    }
690
691    pub fn from_fn(f: impl FnMut(usize) -> T) -> Self {
692        Self {
693            data: (0..M::USIZE).map(f).collect::<Box<_>>(),
694            _len: PhantomData,
695        }
696    }
697
698    pub fn from_constant(c: T) -> Self
699    where
700        T: Copy,
701    {
702        Self {
703            data: (0..M::USIZE).map(|_| c).collect::<Box<_>>(),
704            _len: PhantomData,
705        }
706    }
707}
708
709impl<T: Sized, M: Positive> Display for HeapArray<T, M>
710where
711    T: Display,
712{
713    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
714        write!(f, "[")?;
715        for (i, item) in self.data.iter().enumerate() {
716            if i != 0 {
717                write!(f, ", ")?;
718            }
719            write!(f, "{item}")?;
720        }
721        write!(f, "]")
722    }
723}
724
725#[cfg(test)]
726pub mod tests {
727    use hybrid_array::sizes::{U2, U3, U6};
728    use typenum::{U1, U4};
729
730    use super::*;
731
732    #[test]
733    fn test_heap_array() {
734        let array = HeapArray::<_, U3>::from_fn(|i| i);
735        assert_eq!(array.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
736    }
737
738    #[test]
739    fn test_default() {
740        let array = HeapArray::<usize, U3>::default();
741        assert_eq!(array.len(), 3);
742    }
743
744    #[test]
745    fn test_heap_array_split_last() {
746        let array = HeapArray::<_, U6>::from_fn(|i| i);
747        let (first, last) = array.split_last::<U2>();
748        assert_eq!(first.into_iter().collect::<Vec<_>>(), vec![0, 1, 2, 3]);
749        assert_eq!(last.into_iter().collect::<Vec<_>>(), vec![4, 5]);
750    }
751
752    #[test]
753    fn test_heap_array_from_array() {
754        let array = Array::<_, U3>::from_fn(|i| i);
755        let heap_array = HeapArray::<_, U3>::from(array);
756        assert_eq!(heap_array.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
757    }
758
759    #[test]
760    fn test_heap_array_from_vec() {
761        let vec = vec![0, 1, 2];
762        let heap_array = HeapArray::<_, U3>::try_from(vec).unwrap();
763        assert_eq!(heap_array.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
764
765        let vec = vec![0, 1];
766        let heap_array = HeapArray::<_, U3>::try_from(vec);
767        assert!(heap_array.is_err());
768    }
769
770    #[test]
771    fn test_heap_array_from_iter() {
772        let heap_array = HeapArray::<_, U3>::from_fn(|i| i);
773        assert_eq!(heap_array.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
774    }
775
776    #[test]
777    #[should_panic]
778    fn test_heap_array_from_iter_wrong_size() {
779        HeapArray::<_, U2>::from_iter(0..3);
780    }
781
782    #[test]
783    fn test_heap_array_deserialize() {
784        let array = HeapArray::<usize, U6>::from_fn(|i| i);
785        let serialized = bincode::serialize(&array).unwrap();
786        bincode::deserialize::<HeapArray<usize, U6>>(&serialized).unwrap();
787
788        // With the new tuple-based serialization (which doesn't include length),
789        // we can't detect length mismatches unless we use strict deserialization
790        // that rejects trailing bytes.
791        use bincode::Options;
792        let config = bincode::DefaultOptions::new()
793            .with_fixint_encoding()
794            .reject_trailing_bytes();
795
796        let wrong_deserialize = config.deserialize::<HeapArray<usize, U3>>(&serialized);
797        assert!(wrong_deserialize.is_err());
798    }
799
800    #[test]
801    fn test_heap_array_split() {
802        let array = HeapArray::<_, U6>::from_fn(|i| i);
803        let (first, second) = array.split::<U4, U2>();
804        assert_eq!(first.into_iter().collect::<Vec<_>>(), vec![0, 1, 2, 3]);
805        assert_eq!(second.into_iter().collect::<Vec<_>>(), vec![4, 5]);
806
807        let (first, second) = array.split_halves::<U3>();
808        assert_eq!(first.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
809        assert_eq!(second.into_iter().collect::<Vec<_>>(), vec![3, 4, 5]);
810
811        // let (first, second) = array.split::<U4, U1>(); --> doesn't compile
812
813        // let (first, second) = array.split_halves::<U2>(); --> doesn't compile
814    }
815
816    #[test]
817    fn test_heap_array_split3() {
818        let array = HeapArray::<_, U6>::from_fn(|i| i);
819        let (first, second, third) = array.split3::<U3, U2, U1>();
820        assert_eq!(first.into_iter().collect::<Vec<_>>(), vec![0, 1, 2]);
821        assert_eq!(second.into_iter().collect::<Vec<_>>(), vec![3, 4]);
822        assert_eq!(third.into_iter().collect::<Vec<_>>(), vec![5]);
823
824        let (first, second, third) = array.split_thirds::<U2>();
825        assert_eq!(first.into_iter().collect::<Vec<_>>(), vec![0, 1]);
826        assert_eq!(second.into_iter().collect::<Vec<_>>(), vec![2, 3]);
827        assert_eq!(third.into_iter().collect::<Vec<_>>(), vec![4, 5]);
828
829        // let (a1, a2, a3) = array.split3::<U3, U2, U2>(); // doesn't compile
830
831        // let (a1, a2, a3) = array.split_thirds::<U2>(); // doesn't compile
832    }
833
834    #[test]
835    fn test_heap_array_wrap_transparent() {
836        #[repr(transparent)]
837        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
838        struct Wrap(u32);
839        // SAFETY: `Wrap` is `#[repr(transparent)]` over `u32`.
840        unsafe impl bytemuck::TransparentWrapper<u32> for Wrap {}
841
842        let array = HeapArray::<u32, U3>::from_fn(|i| (i as u32) * 10);
843        let wrapped: HeapArray<Wrap, U3> = array.wrap_transparent();
844        assert_eq!(
845            wrapped.into_iter().collect::<Vec<_>>(),
846            vec![Wrap(0), Wrap(10), Wrap(20)],
847        );
848    }
849
850    #[test]
851    fn test_heap_array_peel_transparent() {
852        #[repr(transparent)]
853        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
854        struct Wrap(u32);
855        // SAFETY: `Wrap` is `#[repr(transparent)]` over `u32`.
856        unsafe impl bytemuck::TransparentWrapper<u32> for Wrap {}
857
858        let array = HeapArray::<Wrap, U3>::from_fn(|i| Wrap((i as u32) * 10));
859        let peeled: HeapArray<u32, U3> = array.peel_transparent();
860        assert_eq!(peeled.into_iter().collect::<Vec<_>>(), vec![0, 10, 20]);
861    }
862
863    #[test]
864    fn test_heap_array_wrap_peel_roundtrip() {
865        #[repr(transparent)]
866        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
867        struct Wrap(u32);
868        // SAFETY: `Wrap` is `#[repr(transparent)]` over `u32`.
869        unsafe impl bytemuck::TransparentWrapper<u32> for Wrap {}
870
871        let original = HeapArray::<u32, U4>::from_fn(|i| i as u32 + 1);
872        let expected = original.clone().into_iter().collect::<Vec<_>>();
873        let roundtripped: HeapArray<u32, U4> =
874            original.wrap_transparent::<Wrap>().peel_transparent();
875        assert_eq!(roundtripped.into_iter().collect::<Vec<_>>(), expected);
876    }
877
878    #[test]
879    fn test_heap_array_wincode_roundtrip() {
880        // Test static zero-copy type
881        let array = HeapArray::<u32, U4>::from_fn(|i| (i * 10) as u32);
882        let ser = wincode::serialize(&array).unwrap();
883        let bin_ser = bincode::serialize(&array).unwrap();
884        let deserialized: HeapArray<u32, U4> = wincode::deserialize(&ser).unwrap();
885
886        assert_eq!(ser, bin_ser);
887        assert_eq!(deserialized, array);
888
889        // Test static non-zero-copy type
890        #[derive(
891            Debug, Copy, Clone, PartialEq, SchemaRead, SchemaWrite, Serialize, Deserialize,
892        )]
893        struct NonZeroCopy {
894            a: u8,
895            b: u16,
896        }
897        let array = HeapArray::<NonZeroCopy, U3>::from_fn(|i| NonZeroCopy {
898            a: i as u8,
899            b: (i * 100) as u16,
900        });
901        let ser = wincode::serialize(&array).unwrap();
902        let bin_ser = bincode::serialize(&array).unwrap();
903        let deserialized: HeapArray<NonZeroCopy, U3> = wincode::deserialize(&ser).unwrap();
904        assert_eq!(ser, bin_ser);
905        assert_eq!(deserialized, array);
906
907        // Test dynamically-sized type
908        let array = HeapArray::<String, U2>::from_fn(|i| format!("String {i}"));
909        let ser = wincode::serialize(&array).unwrap();
910        let bin_ser = bincode::serialize(&array).unwrap();
911        let deserialized: HeapArray<String, U2> = wincode::deserialize(&ser).unwrap();
912        assert_eq!(ser, bin_ser);
913        assert_eq!(deserialized, array);
914    }
915}