use super::deletable::Deletable;
use super::keypath::Keypath;
use super::map::DisjointMut;
use super::node::StorageType;
use super::slot::{SlotMut, SlotRef};
use core::fmt::Debug;
use core::marker::PhantomData;
pub struct Array<S, const N: usize> {
keypath: Keypath,
_marker: PhantomData<fn() -> S>,
}
impl<S, const N: usize> Debug for Array<S, N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Array")
.field("keypath", &self.keypath)
.field("len", &N)
.finish()
}
}
impl<S, const N: usize> From<Keypath> for Array<S, N> {
fn from(keypath: Keypath) -> Self {
const { assert!(N <= u32::MAX as usize, "Array length must fit in a u32") };
let _marker = PhantomData;
Self { keypath, _marker }
}
}
impl<S, const N: usize> super::sealed::Sealed for Array<S, N> {}
impl<S, const N: usize> super::node::StorageType for Array<S, N> {}
impl<S, const N: usize> Array<S, N> {
pub const LEN: u32 = N as u32;
pub fn keypath(&self) -> &Keypath {
&self.keypath
}
pub const fn len(&self) -> u32 {
Self::LEN
}
pub const fn is_empty(&self) -> bool {
N == 0
}
}
impl<S: StorageType, const N: usize> Array<S, N> {
pub fn at(&self, index: u32) -> SlotRef<'_, Self, S> {
let slot = S::from(self.make_elem_keypath(index));
SlotRef::new(self, slot)
}
pub fn at_mut(&mut self, index: u32) -> SlotMut<'_, Self, S> {
let slot = S::from(self.make_elem_keypath(index));
SlotMut::new(self, slot)
}
pub fn at_mut_exclusive(&mut self, index: u32) -> SlotMut<'_, Self, S> {
let mut keypath = self.make_elem_keypath(index);
keypath.set_exclusive();
let slot = S::from(keypath);
SlotMut::new(self, slot)
}
pub fn at_disjoint_mut<const M: usize>(
&mut self,
indices: [u32; M],
) -> DisjointMut<'_, Self, S, M> {
for i in 0..M {
for j in (i + 1)..M {
assert!(
indices[i] != indices[j],
"at_disjoint_mut: duplicate indices at positions {i} and {j}"
);
}
}
let slots =
indices.map(|index| S::from(self.make_elem_keypath(index)));
DisjointMut::new(slots)
}
pub fn iter(&self) -> ArrayIter<'_, S, N> {
ArrayIter {
arr: self,
index: 0,
end: Self::LEN,
}
}
pub fn iter_mut(&mut self) -> ArrayIterMut<'_, S, N> {
ArrayIterMut {
arr: self,
index: 0,
end: Self::LEN,
}
}
fn make_elem_keypath(&self, index: u32) -> Keypath {
if index >= Self::LEN {
super::error::oob_throw(N as u64, index as u64);
}
self.keypath.child(&index)
}
}
impl<S: StorageType + Deletable, const N: usize> Array<S, N> {
#[inline(always)]
pub fn delete_at(&mut self, index: u32) {
self.at_mut(index).delete();
}
}
impl<S: StorageType + Deletable, const N: usize> Deletable for Array<S, N> {
fn delete_internal(&mut self, exclusive: bool) {
for i in 0..Self::LEN {
let mut elem = S::from(self.make_elem_keypath(i));
elem.delete_internal(exclusive);
}
}
}
pub struct ArrayIter<'a, S, const N: usize> {
arr: &'a Array<S, N>,
index: u32,
end: u32,
}
impl<'a, S: StorageType, const N: usize> Iterator for ArrayIter<'a, S, N> {
type Item = SlotRef<'a, Array<S, N>, S>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
let elem = S::from(self.arr.make_elem_keypath(self.index));
self.index += 1;
Some(SlotRef::new(self.arr, elem))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.end - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<S: StorageType, const N: usize> ExactSizeIterator
for ArrayIter<'_, S, N>
{
}
impl<S: StorageType, const N: usize> DoubleEndedIterator
for ArrayIter<'_, S, N>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
self.end -= 1;
let elem = S::from(self.arr.make_elem_keypath(self.end));
Some(SlotRef::new(self.arr, elem))
}
}
pub struct ArrayIterMut<'a, S, const N: usize> {
arr: &'a mut Array<S, N>,
index: u32,
end: u32,
}
impl<'a, S: StorageType, const N: usize> Iterator for ArrayIterMut<'a, S, N> {
type Item = SlotMut<'a, Array<S, N>, S>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
let elem = S::from(self.arr.make_elem_keypath(self.index));
self.index += 1;
Some(SlotMut::new_detached(elem))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.end - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<S: StorageType, const N: usize> ExactSizeIterator
for ArrayIterMut<'_, S, N>
{
}
impl<S: StorageType, const N: usize> DoubleEndedIterator
for ArrayIterMut<'_, S, N>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
self.end -= 1;
let elem = S::from(self.arr.make_elem_keypath(self.end));
Some(SlotMut::new_detached(elem))
}
}
impl<'a, S: StorageType, const N: usize> IntoIterator for &'a Array<S, N> {
type Item = SlotRef<'a, Array<S, N>, S>;
type IntoIter = ArrayIter<'a, S, N>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, S: StorageType, const N: usize> IntoIterator for &'a mut Array<S, N> {
type Item = SlotMut<'a, Array<S, N>, S>;
type IntoIter = ArrayIterMut<'a, S, N>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod test_array_slots {
use super::*;
use crate::storage::{Map, Value};
crate::contract_test!(elements_match_map_u32_slots {
let root = Keypath::default().child("A");
let arr: Array<Value<u32>, 4> = Array::from(root.clone());
let map: Map<u32, Value<u32>> = Map::from(root);
for i in 0..4u32 {
assert_eq!(*arr.at(i).key(), *map.at(&i).key());
}
});
}