use super::deletable::Deletable;
use super::keypath::{FramedComponent, Keypath};
use super::map::Map;
use super::node::StorageType;
use super::slot::{SlotMut, SlotRef};
use super::value::Value;
use crate::exn::NoneIfMissing;
use core::fmt::Debug;
pub struct Vector<S> {
keypath: Keypath,
len: Value<u32>,
values: Map<u32, S>,
}
impl<S> Debug for Vector<S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Vector")
.field("keypath", &self.keypath)
.field("len", &self.len)
.finish_non_exhaustive()
}
}
impl<S> From<Keypath> for Vector<S> {
fn from(keypath: Keypath) -> Self {
const LEN_SLOT: FramedComponent = FramedComponent::from_u32(0);
const VALUES_SLOT: FramedComponent = FramedComponent::from_u32(1);
let len_kp = keypath.child_framed(&LEN_SLOT);
let values_kp = keypath.child_framed(&VALUES_SLOT);
Self {
keypath,
len: Value::from(len_kp),
values: Map::from(values_kp),
}
}
}
impl<S> super::sealed::Sealed for Vector<S> {}
impl<S> super::node::StorageType for Vector<S> {}
impl<S> Vector<S> {
pub fn keypath(&self) -> &Keypath {
&self.keypath
}
}
impl<S: StorageType> Vector<S> {
pub fn len(&self) -> u32 {
self.len.try_get().none_if_missing().unwrap_or(0)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn at(&self, index: u32) -> SlotRef<'_, Self, S> {
self.bounds_check(index);
let keypath = self.make_elem_keypath(index);
let slot = S::from(keypath);
SlotRef::new(self, slot)
}
pub fn at_mut(&mut self, index: u32) -> SlotMut<'_, Self, S> {
self.bounds_check(index);
let keypath = self.make_elem_keypath(index);
let slot = S::from(keypath);
SlotMut::new(self, slot)
}
#[must_use = "push_empty_slot increments len immediately; dropping the slot leaves it uninitialized. Use push_with to initialize atomically, or bind with `let _ = ...` if an empty slot is intentional."]
pub fn push_empty_slot(&mut self) -> SlotMut<'_, Self, S> {
let idx = self.len();
let new_len = idx.checked_add(1).unwrap();
self.len.set_exclusive(&new_len);
let keypath = self.make_elem_keypath(idx);
let slot = S::from(keypath);
SlotMut::new(self, slot)
}
pub fn push_with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
let idx = self.len();
let mut slot = S::from(self.make_elem_keypath(idx));
let out = f(&mut slot);
let new_len = idx.checked_add(1).unwrap();
self.len.set_exclusive(&new_len);
out
}
pub fn iter(&self) -> VectorIter<'_, S> {
VectorIter {
vec: self,
index: 0,
len: self.len(),
}
}
pub fn iter_mut(&mut self) -> VectorIterMut<'_, S> {
let len = self.len();
VectorIterMut {
vec: self,
index: 0,
len,
}
}
fn bounds_check(&self, index: u32) {
let len = self.len();
if index >= len {
super::error::oob_throw(len as u64, index as u64);
}
}
fn make_elem_keypath(&self, index: u32) -> Keypath {
self.values.keypath().child(&index)
}
}
impl<S: StorageType + Deletable> Vector<S> {
pub fn pop(&mut self) {
let len = self.len();
if len == 0 {
super::error::oob_throw(0, 0);
}
let new_len = len - 1;
let mut elem = S::from(self.make_elem_keypath(new_len));
elem.delete_exclusive();
self.len.set_exclusive(&new_len);
}
#[inline(always)]
pub fn delete_at(&mut self, index: u32) {
self.at_mut(index).delete();
}
}
impl<S: StorageType + Deletable> Deletable for Vector<S> {
fn delete_internal(&mut self, exclusive: bool) {
let len = self.len();
for i in 0..len {
let mut elem = S::from(self.make_elem_keypath(i));
elem.delete_internal(exclusive);
}
self.len.delete_internal(exclusive);
}
}
pub struct VectorIter<'a, S> {
vec: &'a Vector<S>,
index: u32,
len: u32,
}
impl<'a, S: StorageType> Iterator for VectorIter<'a, S> {
type Item = SlotRef<'a, Vector<S>, S>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.len {
return None;
}
let elem = S::from(self.vec.make_elem_keypath(self.index));
self.index += 1;
Some(SlotRef::new(self.vec, elem))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.len - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<S: StorageType> ExactSizeIterator for VectorIter<'_, S> {}
impl<'a, S: StorageType> DoubleEndedIterator for VectorIter<'a, S> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.index >= self.len {
return None;
}
self.len -= 1;
let elem = S::from(self.vec.make_elem_keypath(self.len));
Some(SlotRef::new(self.vec, elem))
}
}
pub struct VectorIterMut<'a, S> {
vec: &'a mut Vector<S>,
index: u32,
len: u32,
}
impl<'a, S: StorageType> Iterator for VectorIterMut<'a, S> {
type Item = SlotMut<'a, Vector<S>, S>;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.len {
return None;
}
let elem = S::from(self.vec.make_elem_keypath(self.index));
self.index += 1;
Some(SlotMut::new_detached(elem))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.len - self.index) as usize;
(remaining, Some(remaining))
}
}
impl<S: StorageType> ExactSizeIterator for VectorIterMut<'_, S> {}
impl<'a, S: StorageType> DoubleEndedIterator for VectorIterMut<'a, S> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.index >= self.len {
return None;
}
self.len -= 1;
let elem = S::from(self.vec.make_elem_keypath(self.len));
Some(SlotMut::new_detached(elem))
}
}
impl<'a, S: StorageType> IntoIterator for &'a Vector<S> {
type Item = SlotRef<'a, Vector<S>, S>;
type IntoIter = VectorIter<'a, S>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, S: StorageType> IntoIterator for &'a mut Vector<S> {
type Item = SlotMut<'a, Vector<S>, S>;
type IntoIter = VectorIterMut<'a, S>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[cfg(test)]
mod test_vector_slots {
use super::*;
use crate::storage::Value;
crate::contract_test!(fixed_slots_match_runtime_child {
let root = Keypath::default().child("V");
let v: Vector<Value<u32>> = Vector::from(root.clone());
assert_eq!(*v.len.key(), root.child(&0u32).generate_key());
assert!(v.values.keypath().addresses_same_slot(&root.child(&1u32)));
assert!(v.keypath().addresses_same_slot(&root));
});
}