devela/data/list/array/d1/uninit/
methods.rs

1// devela::data::list:array::d1::uninit::methods
2
3use crate::{
4    iif, ArrayUninit, IndexOutOfBounds, MaybeUninit, Mem,
5    PartialSpace::{self, NotEnoughSpace, PartiallyAdded},
6    Storage,
7};
8
9// T, S
10impl<T, const CAP: usize, S: Storage> ArrayUninit<T, CAP, S> {
11    /* construct */
12
13    /// Returns a new uninitialized empty array.
14    pub fn new() -> Self {
15        // WAIT: [MaybeUninit array methods](https://github.com/rust-lang/rust/issues/96097)
16        // let data = MaybeUninit::uninit_array::<CAP>();
17        //
18        #[allow(clippy::uninit_assumed_init)]
19        // SAFETY: we are ensuring elements are only accessed after initialization.
20        let data = unsafe { MaybeUninit::uninit().assume_init() };
21
22        Self { data, init_len: 0 }
23    }
24
25    /// Initializes the array from an iterator until it's either full or the iterator is exhausted.
26    ///
27    /// # Returns
28    /// - Returns a new array initialized with the elements from the `iterator`.
29    /// - Returns [`PartiallyAdded`] if not all elements could be initialized.
30    /// - Returns [`NotEnoughSpace`] if the array had no uninitialized elements.
31    pub fn from_range<I>(iterator: I) -> Result<Self, PartialSpace>
32    where
33        I: IntoIterator<Item = T>,
34    {
35        let mut array = Self::new();
36        let _ = array.init_range(iterator)?;
37        Ok(array)
38    }
39
40    /* query */
41
42    /// Returns the count of initialized elements.
43    #[must_use] #[rustfmt::skip]
44    pub const fn len(&self) -> usize { self.init_len }
45
46    /// Returns `true` if no elements are yet initialized.
47    #[must_use] #[rustfmt::skip]
48    pub const fn is_empty(&self) -> bool { self.init_len == 0 }
49
50    /// Returns `true` if all the elements are already initialized.
51    #[must_use] #[rustfmt::skip]
52    pub const fn is_full(&self) -> bool { self.init_len >= CAP }
53
54    /// Returns `index` back if it's within the range already initialized.
55    ///
56    /// # Errors
57    /// Returns [`IndexOutOfBounds`] if the index is larger than the initialized length.
58    #[rustfmt::skip]
59    pub const fn verify_index(&self, index: usize) -> Result<usize, IndexOutOfBounds> {
60        iif![index < self.init_len; Ok(index); Err(IndexOutOfBounds(Some(index)))]
61    }
62
63    /* get */
64
65    /// Returns a shared reference to an initialized element at a given index.
66    ///
67    /// # Errors
68    /// Returns [`IndexOutOfBounds`] if the index is larger than the initialized length.
69    /// or if the element at that index is not initialized.
70    pub fn get(&self, index: usize) -> Result<&T, IndexOutOfBounds> {
71        let _ = self.verify_index(index)?;
72        // SAFETY: the index is verified
73        Ok(unsafe { self.data[index].assume_init_ref() })
74    }
75
76    /// Returns an exclusive reference to an initialized element at a given index.
77    ///
78    /// # Errors
79    /// Returns [`IndexOutOfBounds`] if the index is larger than the initialized length.
80    /// or if the element at that index is not initialized.
81    pub fn get_mut(&mut self, index: usize) -> Result<&mut T, IndexOutOfBounds> {
82        let _ = self.verify_index(index)?;
83        // SAFETY: the index is verified
84        Ok(unsafe { self.data[index].assume_init_mut() })
85    }
86
87    /* push */
88
89    /// Initializes the next uninitialized element with the provided value.
90    ///
91    /// # Errors
92    /// Returns [`IndexOutOfBounds`] if the index is larger than the initialized length.
93    pub fn init_next(&mut self, value: T) -> Result<(), IndexOutOfBounds> {
94        if self.is_full() {
95            Err(IndexOutOfBounds(None))
96        } else {
97            self.data[self.init_len] = MaybeUninit::new(value);
98            self.init_len += 1;
99            Ok(())
100        }
101    }
102
103    /// Initializes elements from an iterator
104    ///
105    /// Starts at the last initialized element, continues until either the array
106    /// is full or the iterator is exhausted.
107    ///
108    /// # Returns
109    /// - Returns the number of elements initialized.
110    /// - Returns [`PartiallyAdded`] if not all elements could be initialized.
111    /// - Returns [`NotEnoughSpace`] if the array had no uninitialized elements.
112    pub fn init_range<I>(&mut self, values: I) -> Result<usize, PartialSpace>
113    where
114        I: IntoIterator<Item = T>,
115    {
116        if self.is_full() {
117            Err(NotEnoughSpace(None))
118        } else {
119            let start_len = self.init_len;
120            for value in values {
121                if self.is_full() {
122                    return Ok(self.init_len - start_len);
123                }
124                self.data[self.init_len] = MaybeUninit::new(value);
125                self.init_len += 1;
126            }
127            Err(PartiallyAdded(Some(self.init_len - start_len)))
128        }
129    }
130
131    /// Replaces the value at a given index with a new value and returns the old value.
132    /// # Errors
133    /// Returns [`IndexOutOfBounds`] if the index is not within the range of initialized elements.
134    pub fn replace(&mut self, index: usize, value: T) -> Result<T, IndexOutOfBounds> {
135        let index = self.verify_index(index)?;
136        // SAFETY: If the index is verified, the value is initialized
137        let slot = unsafe { self.data[index].assume_init_mut() };
138        Ok(Mem::replace(slot, value))
139    }
140
141    /// Swaps the values at two indices.
142    /// # Errors
143    /// Returns [`IndexOutOfBounds`]
144    /// if either index is not within the range of initialized elements.
145    pub fn swap(&mut self, index1: usize, index2: usize) -> Result<(), IndexOutOfBounds> {
146        let idx1 = self.verify_index(index1)?;
147        let idx2 = self.verify_index(index2)?;
148        // SAFETY: If the indices are verified, the values are initialized
149        unsafe {
150            core::ptr::swap(self.data[idx1].assume_init_mut(), self.data[idx2].assume_init_mut());
151        }
152        Ok(())
153    }
154}