1use super::deletable::Deletable;
2use super::keypath::Keypath;
3use super::map::DisjointMut;
4use super::node::StorageType;
5use super::slot::{SlotMut, SlotRef};
6use core::fmt::Debug;
7use core::marker::PhantomData;
8
9pub struct Array<S, const N: usize> {
29 keypath: Keypath,
30 _marker: PhantomData<fn() -> S>,
31}
32
33impl<S, const N: usize> Debug for Array<S, N> {
34 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
35 f.debug_struct("Array")
36 .field("keypath", &self.keypath)
37 .field("len", &N)
38 .finish()
39 }
40}
41
42impl<S, const N: usize> From<Keypath> for Array<S, N> {
43 fn from(keypath: Keypath) -> Self {
44 const { assert!(N <= u32::MAX as usize, "Array length must fit in a u32") };
45 let _marker = PhantomData;
46 Self { keypath, _marker }
47 }
48}
49
50impl<S, const N: usize> super::sealed::Sealed for Array<S, N> {}
51impl<S, const N: usize> super::node::StorageType for Array<S, N> {}
52
53impl<S, const N: usize> Array<S, N> {
54 pub const LEN: u32 = N as u32;
56
57 pub fn keypath(&self) -> &Keypath {
58 &self.keypath
59 }
60
61 pub const fn len(&self) -> u32 {
63 Self::LEN
64 }
65
66 pub const fn is_empty(&self) -> bool {
68 N == 0
69 }
70}
71
72impl<S: StorageType, const N: usize> Array<S, N> {
73 pub fn at(&self, index: u32) -> SlotRef<'_, Self, S> {
75 let slot = S::from(self.make_elem_keypath(index));
76 SlotRef::new(self, slot)
77 }
78
79 pub fn at_mut(&mut self, index: u32) -> SlotMut<'_, Self, S> {
81 let slot = S::from(self.make_elem_keypath(index));
82 SlotMut::new(self, slot)
83 }
84
85 pub fn at_mut_exclusive(&mut self, index: u32) -> SlotMut<'_, Self, S> {
89 let mut keypath = self.make_elem_keypath(index);
90 keypath.set_exclusive();
91 let slot = S::from(keypath);
92 SlotMut::new(self, slot)
93 }
94
95 pub fn at_disjoint_mut<const M: usize>(
100 &mut self,
101 indices: [u32; M],
102 ) -> DisjointMut<'_, Self, S, M> {
103 for i in 0..M {
104 for j in (i + 1)..M {
105 assert!(
106 indices[i] != indices[j],
107 "at_disjoint_mut: duplicate indices at positions {i} and {j}"
108 );
109 }
110 }
111 let slots =
112 indices.map(|index| S::from(self.make_elem_keypath(index)));
113 DisjointMut::new(slots)
114 }
115
116 pub fn iter(&self) -> ArrayIter<'_, S, N> {
119 ArrayIter {
120 arr: self,
121 index: 0,
122 end: Self::LEN,
123 }
124 }
125
126 pub fn iter_mut(&mut self) -> ArrayIterMut<'_, S, N> {
129 ArrayIterMut {
130 arr: self,
131 index: 0,
132 end: Self::LEN,
133 }
134 }
135
136 fn make_elem_keypath(&self, index: u32) -> Keypath {
137 if index >= Self::LEN {
138 super::error::oob_throw(N as u64, index as u64);
139 }
140 self.keypath.child(&index)
141 }
142}
143
144impl<S: StorageType + Deletable, const N: usize> Array<S, N> {
145 #[inline(always)]
148 pub fn delete_at(&mut self, index: u32) {
149 self.at_mut(index).delete();
150 }
151}
152
153impl<S: StorageType + Deletable, const N: usize> Deletable for Array<S, N> {
154 fn delete_internal(&mut self, exclusive: bool) {
155 for i in 0..Self::LEN {
156 let mut elem = S::from(self.make_elem_keypath(i));
157 elem.delete_internal(exclusive);
158 }
159 }
160}
161
162pub struct ArrayIter<'a, S, const N: usize> {
164 arr: &'a Array<S, N>,
165 index: u32,
166 end: u32,
167}
168
169impl<'a, S: StorageType, const N: usize> Iterator for ArrayIter<'a, S, N> {
170 type Item = SlotRef<'a, Array<S, N>, S>;
171
172 fn next(&mut self) -> Option<Self::Item> {
173 if self.index >= self.end {
174 return None;
175 }
176 let elem = S::from(self.arr.make_elem_keypath(self.index));
177 self.index += 1;
178 Some(SlotRef::new(self.arr, elem))
179 }
180
181 fn size_hint(&self) -> (usize, Option<usize>) {
182 let remaining = (self.end - self.index) as usize;
183 (remaining, Some(remaining))
184 }
185}
186
187impl<S: StorageType, const N: usize> ExactSizeIterator
188 for ArrayIter<'_, S, N>
189{
190}
191
192impl<S: StorageType, const N: usize> DoubleEndedIterator
193 for ArrayIter<'_, S, N>
194{
195 fn next_back(&mut self) -> Option<Self::Item> {
196 if self.index >= self.end {
197 return None;
198 }
199 self.end -= 1;
200 let elem = S::from(self.arr.make_elem_keypath(self.end));
201 Some(SlotRef::new(self.arr, elem))
202 }
203}
204
205pub struct ArrayIterMut<'a, S, const N: usize> {
207 arr: &'a mut Array<S, N>,
208 index: u32,
209 end: u32,
210}
211
212impl<'a, S: StorageType, const N: usize> Iterator for ArrayIterMut<'a, S, N> {
213 type Item = SlotMut<'a, Array<S, N>, S>;
214
215 fn next(&mut self) -> Option<Self::Item> {
216 if self.index >= self.end {
217 return None;
218 }
219 let elem = S::from(self.arr.make_elem_keypath(self.index));
220 self.index += 1;
221 Some(SlotMut::new_detached(elem))
224 }
225
226 fn size_hint(&self) -> (usize, Option<usize>) {
227 let remaining = (self.end - self.index) as usize;
228 (remaining, Some(remaining))
229 }
230}
231
232impl<S: StorageType, const N: usize> ExactSizeIterator
233 for ArrayIterMut<'_, S, N>
234{
235}
236
237impl<S: StorageType, const N: usize> DoubleEndedIterator
238 for ArrayIterMut<'_, S, N>
239{
240 fn next_back(&mut self) -> Option<Self::Item> {
241 if self.index >= self.end {
242 return None;
243 }
244 self.end -= 1;
245 let elem = S::from(self.arr.make_elem_keypath(self.end));
246 Some(SlotMut::new_detached(elem))
247 }
248}
249
250impl<'a, S: StorageType, const N: usize> IntoIterator for &'a Array<S, N> {
251 type Item = SlotRef<'a, Array<S, N>, S>;
252 type IntoIter = ArrayIter<'a, S, N>;
253
254 fn into_iter(self) -> Self::IntoIter {
255 self.iter()
256 }
257}
258
259impl<'a, S: StorageType, const N: usize> IntoIterator for &'a mut Array<S, N> {
260 type Item = SlotMut<'a, Array<S, N>, S>;
261 type IntoIter = ArrayIterMut<'a, S, N>;
262
263 fn into_iter(self) -> Self::IntoIter {
264 self.iter_mut()
265 }
266}
267
268#[cfg(test)]
269mod test_array_slots {
270 use super::*;
271 use crate::storage::{Map, Value};
272
273 crate::contract_test!(elements_match_map_u32_slots {
276 let root = Keypath::default().child("A");
277 let arr: Array<Value<u32>, 4> = Array::from(root.clone());
278 let map: Map<u32, Value<u32>> = Map::from(root);
279 for i in 0..4u32 {
280 assert_eq!(*arr.at(i).key(), *map.at(&i).key());
281 }
282 });
283}