Skip to main content

fbl/
array.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use core::convert::Infallible;
8use core::mem::MaybeUninit;
9use core::ops::{Deref, DerefMut};
10use core::pin::Pin;
11use core::ptr::slice_from_raw_parts_mut;
12use kalloc::{AllocError, Allocator, Box, DefaultAllocator};
13use pin_init::PinInit;
14use zerocopy::FromZeros;
15
16/// A fixed-size array that takes ownership of its elements.
17/// This is a Rust analog to `fbl::Array` in C++.
18pub struct Array<T, A: Allocator = DefaultAllocator> {
19    buf: Box<[T], A>,
20}
21
22zr::static_assert!(core::mem::size_of::<Array<u32>>() == 16);
23zr::static_assert!(core::mem::align_of::<Array<u32>>() == 8);
24
25impl<T, A: Allocator> Array<T, A> {
26    /// Creates an empty array with the given allocator.
27    pub const fn new_in(allocator: A) -> Self {
28        Self { buf: Box::empty_slice_in(allocator) }
29    }
30
31    /// Creates an array from a Box.
32    pub fn from_box(buf: Box<[T], A>) -> Self {
33        Self { buf }
34    }
35
36    /// Allocates a new array of the given length, default-constructing each element.
37    pub fn try_new_in(len: usize, allocator: A) -> Result<Self, AllocError>
38    where
39        T: Default,
40    {
41        let mut b = Box::<[T], A>::try_new_uninit_slice_in(len, allocator)?;
42        for i in 0..len {
43            b[i].write(T::default());
44        }
45        // SAFETY: All elements have been initialized.
46        Ok(Self { buf: unsafe { b.assume_init() } })
47    }
48
49    /// Allocates a new pinned array of the given length with the given allocator, initializing
50    /// each element in place with a pin-initializer returned by `init`.
51    ///
52    /// This supports element types which must not move once initialized (and hence cannot
53    /// implement `Default`), such as `DoublyLinkedList`. See `try_new_pin_init` for details.
54    pub fn try_new_pin_init_in<I, F>(
55        len: usize,
56        mut init: F,
57        allocator: A,
58    ) -> Result<Pin<Self>, AllocError>
59    where
60        F: FnMut() -> I,
61        I: PinInit<T, Infallible>,
62    {
63        let mut b = Box::<[T], A>::try_new_uninit_slice_in(len, allocator)?;
64
65        // Drops the elements initialized so far if `init` (or an initializer) panics, so that
66        // pinned elements are never deallocated without being dropped first.
67        struct InitGuard<'a, T> {
68            slots: &'a mut [MaybeUninit<T>],
69            initialized: usize,
70        }
71
72        impl<T> Drop for InitGuard<'_, T> {
73            fn drop(&mut self) {
74                for slot in &mut self.slots[..self.initialized] {
75                    // SAFETY: The first `initialized` slots have been initialized.
76                    unsafe { slot.assume_init_drop() };
77                }
78            }
79        }
80
81        let mut guard = InitGuard { slots: &mut b, initialized: 0 };
82        while guard.initialized < len {
83            let slot = guard.slots[guard.initialized].as_mut_ptr();
84            // SAFETY: `slot` is a valid, aligned, writable pointer to uninitialized memory inside
85            // the newly allocated buffer. The buffer is never moved or resized, and it is returned
86            // as a `Pin` below (or its initialized elements are dropped in place by `guard`), so
87            // the element is never moved before it is dropped, satisfying `PinInit`.
88            match unsafe { init().__pinned_init(slot) } {
89                Ok(()) => guard.initialized += 1,
90                Err(never) => match never {},
91            }
92        }
93        core::mem::forget(guard);
94
95        // SAFETY: All elements have been initialized by the loop above.
96        Ok(Self { buf: unsafe { b.assume_init() } }.into_pin())
97    }
98
99    /// Converts the array into a `Pin<Array<T, A>>`, pinning its elements in place.
100    ///
101    /// This does not allocate or move the elements, which live in a heap allocation that is
102    /// never moved for the lifetime of the array.
103    pub const fn into_pin(self) -> Pin<Self> {
104        // SAFETY: The elements of the array live in a heap allocation which `Array` never moves
105        // or reallocates, its `Deref` and `DerefMut` implementations hand out references to them
106        // in place, and dropping the array drops the elements in place. The returned `Pin`
107        // prevents safe code from obtaining the array (or a mutable reference to its elements)
108        // unless `T: Unpin`.
109        unsafe { Pin::new_unchecked(self) }
110    }
111
112    /// Allocates a new uninitialized array of the given length with the given allocator.
113    pub fn try_new_uninit_slice_in(
114        len: usize,
115        allocator: A,
116    ) -> Result<Array<MaybeUninit<T>, A>, AllocError> {
117        Ok(Array { buf: Box::<[T], A>::try_new_uninit_slice_in(len, allocator)? })
118    }
119
120    /// Consumes the array, returning a raw slice pointer and the allocator.
121    ///
122    /// The memory will be leaked, and never deallocated unless reconstructed.
123    pub fn into_raw_with_allocator(self) -> (*mut [T], A) {
124        Box::into_raw_with_allocator(self.buf)
125    }
126
127    /// Consumes the array, returning a pointer to the first element, the element count, and the
128    /// allocator.
129    ///
130    /// The memory will be leaked, and never deallocated unless reconstructed.
131    pub fn into_raw_parts_with_allocator(self) -> (*mut T, usize, A) {
132        let (slice_ptr, allocator) = self.into_raw_with_allocator();
133        (slice_ptr as *mut T, slice_ptr.len(), allocator)
134    }
135
136    /// Constructs an array from a raw slice pointer and allocator.
137    ///
138    /// # Safety
139    ///
140    /// - For non-zero-sized types, the pointer must be valid and have been allocated
141    ///   by `allocator` with a layout matching the slice length elements of `T`.
142    pub unsafe fn from_raw_in(ptr: *mut [T], allocator: A) -> Self {
143        Self { buf: unsafe { Box::from_raw_in(ptr, allocator) } }
144    }
145
146    /// Constructs an array from a raw pointer to elements and length with the given allocator.
147    ///
148    /// This is particularly convenient when receiving an array from C/FFI boundaries.
149    ///
150    /// # Safety
151    ///
152    /// - For non-zero-sized types, the pointer must be valid and have been allocated
153    ///   by `allocator` with a layout matching `len` elements of `T`.
154    pub unsafe fn from_raw_parts_in(ptr: *mut T, len: usize, allocator: A) -> Self {
155        let slice_ptr = slice_from_raw_parts_mut(ptr, len);
156        unsafe { Self::from_raw_in(slice_ptr, allocator) }
157    }
158
159    /// Returns the number of elements in the array.
160    pub fn len(&self) -> usize {
161        self.buf.len()
162    }
163
164    /// Returns true if the array is empty.
165    pub fn is_empty(&self) -> bool {
166        self.buf.is_empty()
167    }
168
169    /// Consumes the array and returns the inner Box.
170    pub fn into_box(self) -> Box<[T], A> {
171        self.buf
172    }
173}
174
175impl<T: FromZeros, A: Allocator> Array<T, A> {
176    /// Allocates a new zero-initialized array of the given length with the given allocator.
177    pub fn try_new_zeroed_slice_in(len: usize, allocator: A) -> Result<Self, AllocError> {
178        Ok(Self { buf: Box::<[T], A>::try_new_zeroed_slice_in(len, allocator)? })
179    }
180}
181
182impl<T: FromZeros> Array<T, DefaultAllocator> {
183    /// Allocates a new zero-initialized array of the given length using the default allocator.
184    pub fn try_new_zeroed_slice(len: usize) -> Result<Self, AllocError> {
185        Self::try_new_zeroed_slice_in(len, DefaultAllocator)
186    }
187}
188
189impl<T> Array<T, DefaultAllocator> {
190    /// Creates an empty array using the default allocator.
191    pub const fn new() -> Self {
192        Self { buf: Box::empty_slice() }
193    }
194
195    /// Allocates a new array of the given length, default-constructing each element.
196    pub fn try_new(len: usize) -> Result<Self, AllocError>
197    where
198        T: Default,
199    {
200        Self::try_new_in(len, DefaultAllocator)
201    }
202
203    /// Allocates a new pinned array of the given length using the default allocator,
204    /// initializing each element in place with a pin-initializer returned by `init`.
205    ///
206    /// This supports element types which must not move once initialized (and hence cannot
207    /// implement `Default`), such as `DoublyLinkedList`:
208    ///
209    /// ```rust
210    /// # use fbl::{Array, DoublyLinkedList, UniquePtr};
211    /// # #[derive(fbl::DoublyLinkedListContainable, fbl::Recyclable)]
212    /// # struct Foo {
213    /// #     #[dll_node]
214    /// #     node: fbl::DoublyLinkedListNode<Foo>,
215    /// # }
216    /// type List = DoublyLinkedList<UniquePtr<Foo>>;
217    /// let lists = Array::<List>::try_new_pin_init(4, List::new).unwrap();
218    /// assert!(lists.iter().all(|list| list.is_empty()));
219    /// ```
220    ///
221    /// The elements are never moved by `Array`. The array is returned as a `Pin` so that safe code
222    /// cannot move them either (e.g. with `core::mem::swap` through `DerefMut`): shared access to
223    /// the elements is available through `Deref`, while mutable access requires `unsafe` code
224    /// (e.g. `Pin::get_unchecked_mut` on `Pin::as_mut`) which must not move any element out of
225    /// the array. If an initializer panics, the elements initialized so far are dropped in place.
226    pub fn try_new_pin_init<I, F>(len: usize, init: F) -> Result<Pin<Self>, AllocError>
227    where
228        F: FnMut() -> I,
229        I: PinInit<T, Infallible>,
230    {
231        Self::try_new_pin_init_in(len, init, DefaultAllocator)
232    }
233
234    /// Allocates a new uninitialized array of the given length using the default allocator.
235    pub fn try_new_uninit_slice(
236        len: usize,
237    ) -> Result<Array<MaybeUninit<T>, DefaultAllocator>, AllocError> {
238        Self::try_new_uninit_slice_in(len, DefaultAllocator)
239    }
240
241    /// Consumes the array, returning a raw slice pointer.
242    ///
243    /// The memory will be leaked, and never deallocated unless reconstructed.
244    pub fn into_raw(self) -> *mut [T] {
245        let (ptr, _) = self.into_raw_with_allocator();
246        ptr
247    }
248
249    /// Consumes the array, returning a pointer to the first element and the element count.
250    ///
251    /// This is particularly convenient when passing an array across C/FFI boundaries.
252    /// The memory will be leaked, and never deallocated unless reconstructed.
253    pub fn into_raw_parts(self) -> (*mut T, usize) {
254        let (ptr, len, _) = self.into_raw_parts_with_allocator();
255        (ptr, len)
256    }
257
258    /// Constructs an array from a raw slice pointer using the default allocator.
259    ///
260    /// # Safety
261    ///
262    /// - For non-zero-sized types, the pointer must be valid and have been allocated
263    ///   by the default allocator with a layout matching the slice length elements of `T`.
264    pub unsafe fn from_raw(ptr: *mut [T]) -> Self {
265        unsafe { Self::from_raw_in(ptr, DefaultAllocator) }
266    }
267
268    /// Constructs an array from a raw pointer to elements and length using the default allocator.
269    ///
270    /// This is particularly convenient when receiving an array from C/FFI boundaries.
271    ///
272    /// # Safety
273    ///
274    /// - For non-zero-sized types, the pointer must be valid and have been allocated
275    ///   by the default allocator with a layout matching `len` elements of `T`.
276    pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
277        unsafe { Self::from_raw_parts_in(ptr, len, DefaultAllocator) }
278    }
279}
280
281impl<T, A: Allocator> Array<MaybeUninit<T>, A> {
282    /// Converts to `Array<T, A>`.
283    ///
284    /// # Safety
285    ///
286    /// The caller must guarantee that all elements of the array are initialized.
287    pub unsafe fn assume_init(self) -> Array<T, A> {
288        Array { buf: unsafe { self.buf.assume_init() } }
289    }
290}
291
292impl<T, A: Allocator> Deref for Array<T, A> {
293    type Target = [T];
294
295    fn deref(&self) -> &Self::Target {
296        &self.buf
297    }
298}
299
300impl<T, A: Allocator> DerefMut for Array<T, A> {
301    fn deref_mut(&mut self) -> &mut Self::Target {
302        &mut self.buf
303    }
304}
305
306impl<T> Default for Array<T, DefaultAllocator> {
307    fn default() -> Self {
308        Self::new()
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use super::*;
315    use core::cell::Cell;
316    use core::ptr::NonNull;
317
318    #[derive(Debug, PartialEq, Eq)]
319    struct TestState {
320        live_obj_count: Cell<usize>,
321        ctor_count: Cell<usize>,
322        dtor_count: Cell<usize>,
323        alloc_count: Cell<usize>,
324        fail_threshold: Cell<usize>,
325    }
326
327    impl Default for TestState {
328        fn default() -> Self {
329            Self {
330                live_obj_count: Cell::new(0),
331                ctor_count: Cell::new(0),
332                dtor_count: Cell::new(0),
333                alloc_count: Cell::new(0),
334                fail_threshold: Cell::new(usize::MAX),
335            }
336        }
337    }
338
339    #[derive(Clone)]
340    struct TestAllocator<'a> {
341        state: &'a TestState,
342    }
343
344    impl<'a> kalloc::Allocator for TestAllocator<'a> {
345        fn allocate(&self, layout: core::alloc::Layout) -> Result<NonNull<[u8]>, AllocError> {
346            let current = self.state.alloc_count.get();
347            self.state.alloc_count.set(current + 1);
348            if current >= self.state.fail_threshold.get() {
349                return Err(AllocError);
350            }
351            DefaultAllocator::default().allocate(layout)
352        }
353
354        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: core::alloc::Layout) {
355            unsafe { DefaultAllocator::default().deallocate(ptr, layout) }
356        }
357
358        unsafe fn grow(
359            &self,
360            ptr: NonNull<u8>,
361            old_layout: core::alloc::Layout,
362            new_layout: core::alloc::Layout,
363        ) -> Result<NonNull<[u8]>, AllocError> {
364            let current = self.state.alloc_count.get();
365            self.state.alloc_count.set(current + 1);
366            if current >= self.state.fail_threshold.get() {
367                return Err(AllocError);
368            }
369            unsafe { DefaultAllocator::default().grow(ptr, old_layout, new_layout) }
370        }
371
372        unsafe fn shrink(
373            &self,
374            ptr: NonNull<u8>,
375            old_layout: core::alloc::Layout,
376            new_layout: core::alloc::Layout,
377        ) -> Result<NonNull<[u8]>, AllocError> {
378            let current = self.state.alloc_count.get();
379            self.state.alloc_count.set(current + 1);
380            if current >= self.state.fail_threshold.get() {
381                return Err(AllocError);
382            }
383            unsafe { DefaultAllocator::default().shrink(ptr, old_layout, new_layout) }
384        }
385
386        fn allocate_zeroed(
387            &self,
388            layout: core::alloc::Layout,
389        ) -> Result<NonNull<[u8]>, AllocError> {
390            let current = self.state.alloc_count.get();
391            self.state.alloc_count.set(current + 1);
392            if current >= self.state.fail_threshold.get() {
393                return Err(AllocError);
394            }
395            DefaultAllocator::default().allocate_zeroed(layout)
396        }
397    }
398
399    #[derive(Debug, Eq, PartialEq)]
400    struct TestObject<'a> {
401        val: usize,
402        alive: bool,
403        state: &'a TestState,
404    }
405
406    impl<'a> TestObject<'a> {
407        fn new(val: usize, state: &'a TestState) -> Self {
408            state.live_obj_count.set(state.live_obj_count.get() + 1);
409            state.ctor_count.set(state.ctor_count.get() + 1);
410            TestObject { val, alive: true, state }
411        }
412    }
413
414    impl<'a> Drop for TestObject<'a> {
415        fn drop(&mut self) {
416            if self.alive {
417                self.state.live_obj_count.set(self.state.live_obj_count.get() - 1);
418                self.state.dtor_count.set(self.state.dtor_count.get() + 1);
419            }
420        }
421    }
422
423    #[test]
424    fn test_empty_array() {
425        let a: Array<u32> = Array::new();
426        assert_eq!(a.len(), 0);
427        assert!(a.is_empty());
428    }
429
430    #[test]
431    fn test_try_new() {
432        let a = Array::<u32>::try_new(5).unwrap();
433        assert_eq!(a.len(), 5);
434        for i in 0..5 {
435            assert_eq!(a[i], 0);
436        }
437    }
438
439    #[test]
440    fn test_deref() {
441        let mut a = Array::<u32>::try_new(2).unwrap();
442        a[0] = 10;
443        a[1] = 20;
444
445        let slice: &[u32] = &a;
446        assert_eq!(slice, &[10, 20]);
447
448        let slice_mut: &mut [u32] = &mut a;
449        slice_mut[0] = 30;
450        assert_eq!(a[0], 30);
451    }
452
453    #[test]
454    fn test_drop_behavior() {
455        let state = TestState::default();
456        {
457            let mut b = Box::<[TestObject<'_>], TestAllocator<'_>>::try_new_uninit_slice_in(
458                2,
459                TestAllocator { state: &state },
460            )
461            .unwrap();
462            b[0].write(TestObject::new(1, &state));
463            b[1].write(TestObject::new(2, &state));
464            let _a = Array::from_box(unsafe { b.assume_init() });
465            assert_eq!(state.live_obj_count.get(), 2);
466        }
467        assert_eq!(state.live_obj_count.get(), 0);
468        assert_eq!(state.dtor_count.get(), 2);
469    }
470
471    #[test]
472    fn test_allocation_failure() {
473        let state = TestState::default();
474        state.fail_threshold.set(0); // Fail immediately
475
476        let res = Array::<u32, TestAllocator<'_>>::try_new_in(5, TestAllocator { state: &state });
477        assert!(res.is_err());
478    }
479
480    #[test]
481    fn test_try_new_zero_sized() {
482        let state = TestState::default();
483        let a = Array::<u32, TestAllocator<'_>>::try_new_in(0, TestAllocator { state: &state })
484            .unwrap();
485        assert_eq!(a.len(), 0);
486        assert!(a.is_empty());
487    }
488
489    #[test]
490    fn test_non_trivial_default() {
491        #[derive(Debug, PartialEq, Eq)]
492        struct MyInt {
493            value: i32,
494        }
495        impl Default for MyInt {
496            fn default() -> Self {
497                Self { value: 42 }
498            }
499        }
500
501        let a = Array::<MyInt>::try_new(5).unwrap();
502        assert_eq!(a.len(), 5);
503        for i in 0..5 {
504            assert_eq!(a[i].value, 42);
505        }
506    }
507
508    #[test]
509    fn test_array_new_in() {
510        let state = TestState::default();
511        let alloc = TestAllocator { state: &state };
512        let a = Array::<u32, TestAllocator<'_>>::new_in(alloc.clone());
513        assert!(a.is_empty());
514    }
515
516    #[test]
517    fn test_array_default() {
518        let a_def: Array<u32> = Default::default();
519        assert!(a_def.is_empty());
520    }
521
522    #[test]
523    fn test_array_into_box() {
524        let a_try = Array::<u32>::try_new(3).unwrap();
525        let b = a_try.into_box();
526        assert_eq!(b.len(), 3);
527    }
528
529    #[test]
530    fn test_array_test_allocator_happy() {
531        use kalloc::Allocator;
532        let state = TestState::default();
533        let alloc = TestAllocator { state: &state };
534        let layout = core::alloc::Layout::new::<u32>();
535        let ptr = alloc.allocate_zeroed(layout).unwrap();
536
537        let ptr = unsafe {
538            alloc.grow(ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap()).unwrap()
539        };
540
541        let ptr = unsafe {
542            alloc.shrink(ptr.cast(), core::alloc::Layout::array::<u32>(2).unwrap(), layout).unwrap()
543        };
544
545        unsafe {
546            alloc.deallocate(ptr.cast(), layout);
547        }
548    }
549
550    #[test]
551    fn test_array_test_allocator_failure() {
552        use kalloc::Allocator;
553        let state = TestState::default();
554        let alloc = TestAllocator { state: &state };
555        let layout = core::alloc::Layout::new::<u32>();
556
557        // Set fail threshold to fail immediately
558        state.fail_threshold.set(0);
559
560        assert!(alloc.allocate_zeroed(layout).is_err());
561
562        let dummy_ptr = core::ptr::NonNull::<u8>::dangling();
563        assert!(
564            unsafe {
565                alloc.grow(dummy_ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap())
566            }
567            .is_err()
568        );
569        assert!(
570            unsafe {
571                alloc.shrink(
572                    dummy_ptr.cast(),
573                    core::alloc::Layout::array::<u32>(2).unwrap(),
574                    layout,
575                )
576            }
577            .is_err()
578        );
579    }
580
581    #[test]
582    fn test_try_new_zeroed_slice() {
583        let arr = Array::<u32>::try_new_zeroed_slice(4).unwrap();
584        assert_eq!(arr.len(), 4);
585        for &val in arr.iter() {
586            assert_eq!(val, 0);
587        }
588
589        let state = TestState::default();
590        let arr_alloc = Array::<u32, TestAllocator<'_>>::try_new_zeroed_slice_in(
591            3,
592            TestAllocator { state: &state },
593        )
594        .unwrap();
595        assert_eq!(arr_alloc.len(), 3);
596        assert_eq!(state.alloc_count.get(), 1);
597        for &val in arr_alloc.iter() {
598            assert_eq!(val, 0);
599        }
600    }
601
602    #[test]
603    fn test_try_new_uninit_slice_and_assume_init() {
604        let mut uninit = Array::<u32>::try_new_uninit_slice(3).unwrap();
605        assert_eq!(uninit.len(), 3);
606        for i in 0..3 {
607            uninit[i].write((i * 10) as u32);
608        }
609        let arr = unsafe { uninit.assume_init() };
610        assert_eq!(arr.len(), 3);
611        assert_eq!(&arr[..], &[0, 10, 20]);
612    }
613
614    #[test]
615    fn test_uninit_slice_drop_behavior() {
616        let state = TestState::default();
617        {
618            let mut uninit = Array::<TestObject<'_>, TestAllocator<'_>>::try_new_uninit_slice_in(
619                2,
620                TestAllocator { state: &state },
621            )
622            .unwrap();
623            uninit[0].write(TestObject::new(10, &state));
624            uninit[1].write(TestObject::new(20, &state));
625            let arr = unsafe { uninit.assume_init() };
626            assert_eq!(state.live_obj_count.get(), 2);
627            assert_eq!(arr[0].val, 10);
628            assert_eq!(arr[1].val, 20);
629        }
630        assert_eq!(state.live_obj_count.get(), 0);
631        assert_eq!(state.dtor_count.get(), 2);
632    }
633
634    #[test]
635    fn test_into_and_from_raw_parts() {
636        let mut arr = Array::<u32>::try_new(3).unwrap();
637        arr[0] = 100;
638        arr[1] = 200;
639        arr[2] = 300;
640
641        let (ptr, len) = arr.into_raw_parts();
642        assert_eq!(len, 3);
643        assert!(!ptr.is_null());
644
645        let reconstructed = unsafe { Array::<u32>::from_raw_parts(ptr, len) };
646        assert_eq!(reconstructed.len(), 3);
647        assert_eq!(&reconstructed[..], &[100, 200, 300]);
648    }
649
650    #[test]
651    fn test_into_and_from_raw() {
652        let mut arr = Array::<u32>::try_new(2).unwrap();
653        arr[0] = 42;
654        arr[1] = 84;
655
656        let slice_ptr = arr.into_raw();
657        assert_eq!(unsafe { &*slice_ptr }, &[42, 84]);
658
659        let reconstructed = unsafe { Array::<u32>::from_raw(slice_ptr) };
660        assert_eq!(&reconstructed[..], &[42, 84]);
661    }
662
663    #[test]
664    fn test_raw_parts_with_allocator() {
665        let state = TestState::default();
666        let alloc = TestAllocator { state: &state };
667        let mut arr = Array::<u32, TestAllocator<'_>>::try_new_in(2, alloc.clone()).unwrap();
668        arr[0] = 7;
669        arr[1] = 9;
670
671        let (ptr, len, returned_alloc) = arr.into_raw_parts_with_allocator();
672        assert_eq!(len, 2);
673
674        let reconstructed =
675            unsafe { Array::<u32, TestAllocator<'_>>::from_raw_parts_in(ptr, len, returned_alloc) };
676        assert_eq!(&reconstructed[..], &[7, 9]);
677    }
678
679    /// An object which records its own address when it is pin-initialized.
680    #[pin_init::pin_data]
681    struct SelfAddressed {
682        addr: *mut SelfAddressed,
683        #[pin]
684        _pin: core::marker::PhantomPinned,
685    }
686
687    impl SelfAddressed {
688        fn new() -> impl PinInit<Self, Infallible> {
689            pin_init::pin_init!(&this in Self {
690                addr: this.as_ptr(),
691                _pin: core::marker::PhantomPinned,
692            })
693        }
694
695        fn is_at_initial_address(&self) -> bool {
696            core::ptr::eq(self.addr, self)
697        }
698    }
699
700    #[test]
701    fn test_try_new_pin_init() {
702        let mut init_count = 0;
703        let arr = Array::<SelfAddressed>::try_new_pin_init(5, || {
704            init_count += 1;
705            SelfAddressed::new()
706        })
707        .unwrap();
708        assert_eq!(init_count, 5);
709        assert_eq!(arr.len(), 5);
710        assert!(arr.iter().all(SelfAddressed::is_at_initial_address));
711
712        // Moving the array does not move its elements.
713        let moved = arr;
714        assert!(moved.iter().all(SelfAddressed::is_at_initial_address));
715    }
716
717    #[test]
718    fn test_try_new_pin_init_zero_sized() {
719        let mut init_count = 0;
720        let arr = Array::<SelfAddressed>::try_new_pin_init(0, || {
721            init_count += 1;
722            SelfAddressed::new()
723        })
724        .unwrap();
725        assert_eq!(init_count, 0);
726        assert!(arr.is_empty());
727    }
728
729    #[test]
730    fn test_try_new_pin_init_allocation_failure() {
731        let state = TestState::default();
732        state.fail_threshold.set(0); // Fail immediately
733
734        let mut init_count = 0;
735        let res = Array::<SelfAddressed, TestAllocator<'_>>::try_new_pin_init_in(
736            5,
737            || {
738                init_count += 1;
739                SelfAddressed::new()
740            },
741            TestAllocator { state: &state },
742        );
743        assert!(res.is_err());
744        assert_eq!(init_count, 0);
745    }
746
747    #[test]
748    fn test_try_new_pin_init_drop_behavior() {
749        let state = TestState::default();
750        {
751            let mut next_val = 0;
752            let arr = Array::<TestObject<'_>, TestAllocator<'_>>::try_new_pin_init_in(
753                3,
754                || {
755                    next_val += 1;
756                    TestObject::new(next_val, &state)
757                },
758                TestAllocator { state: &state },
759            )
760            .unwrap();
761            assert_eq!(state.alloc_count.get(), 1);
762            assert_eq!(state.live_obj_count.get(), 3);
763            assert_eq!(arr.iter().map(|obj| obj.val).sum::<usize>(), 1 + 2 + 3);
764        }
765        assert_eq!(state.live_obj_count.get(), 0);
766        assert_eq!(state.dtor_count.get(), 3);
767    }
768
769    #[test]
770    fn test_into_pin() {
771        let mut arr = Array::<u32>::try_new(2).unwrap();
772        arr[0] = 1;
773        arr[1] = 2;
774        let elements: *const u32 = arr.as_ptr();
775
776        let mut pinned = arr.into_pin();
777        assert!(core::ptr::eq(pinned.as_ptr(), elements));
778        assert_eq!(&pinned[..], &[1, 2]);
779
780        // Elements which are `Unpin` may still be mutated through the pin.
781        pinned.as_mut().get_mut()[0] = 3;
782        assert_eq!(&pinned[..], &[3, 2]);
783    }
784}