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}