odra_core/
list.rs

1use core::ops::Range;
2
3use alloc::rc::Rc;
4use casper_types::{
5    bytesrepr::{FromBytes, ToBytes},
6    CLTyped
7};
8
9use crate::{
10    module::{ModuleComponent, ModulePrimitive, Revertible},
11    prelude::*,
12    CollectionError, ContractEnv
13};
14
15/// Data structure for an indexed, iterable collection.
16pub struct List<T> {
17    env: Rc<ContractEnv>,
18    index: u8,
19    values: Mapping<u32, T>,
20    current_index: Var<u32>
21}
22
23impl<T> List<T> {
24    /// Returns the ContractEnv.
25    pub fn env(&self) -> ContractEnv {
26        self.env.child(self.index)
27    }
28}
29
30impl<T> ModuleComponent for List<T> {
31    fn instance(env: Rc<ContractEnv>, index: u8) -> Self {
32        Self {
33            env: env.clone(),
34            index,
35            values: Mapping::instance(env.child(index).into(), 0),
36            current_index: Var::instance(env.child(index).into(), 1)
37        }
38    }
39}
40
41impl<T> Revertible for List<T> {
42    fn revert<E: Into<OdraError>>(&self, e: E) -> ! {
43        self.env.revert(e)
44    }
45}
46
47impl<T> ModulePrimitive for List<T> {}
48
49impl<T> List<T> {
50    /// Checks if the collection is empty.
51    pub fn is_empty(&self) -> bool {
52        self.len() == 0
53    }
54
55    /// Gets the collection length.
56    pub fn len(&self) -> u32 {
57        self.current_index.get_or_default()
58    }
59}
60
61impl<T: FromBytes + CLTyped> List<T> {
62    /// Reads collection's n-th value from the storage or returns `None`.
63    pub fn get(&self, index: u32) -> Option<T> {
64        self.values.get(&index)
65    }
66}
67
68impl<T: ToBytes + FromBytes + CLTyped> List<T> {
69    /// Pushes the `value` to the storage.
70    pub fn push(&mut self, value: T) {
71        let next_index = self.len();
72        self.values.set(&next_index, value);
73        self.current_index.set(next_index + 1);
74    }
75
76    /// Replaces the current value with the `value` and returns it.
77    pub fn replace(&mut self, index: u32, value: T) -> T {
78        if index >= self.len() {
79            self.env.revert(CollectionError::IndexOutOfBounds);
80        }
81
82        let prev_value = self.values.get(&index).unwrap_or_revert(self);
83        self.values.set(&index, value);
84        prev_value
85    }
86
87    /// Pops the last value from the storage or returns `None`.
88    pub fn pop(&mut self) -> Option<T> {
89        let next_index = self.len();
90        if next_index == 0 {
91            return None;
92        }
93        let last = next_index - 1;
94        let value = self.values.get(&last).unwrap_or_revert(self);
95        self.current_index.set(last);
96        Some(value)
97    }
98
99    /// Returns an iterator.
100    pub fn iter(&self) -> ListIter<T> {
101        ListIter::new(self)
102    }
103}
104
105/// An iterator over the elements of a `List`.
106///
107/// This struct is created by the [`iter`] method on [`List`]. See its documentation for more.
108///
109/// [`iter`]: struct.List.html#method.iter
110/// [`List`]: struct.List.html
111pub struct ListIter<'a, T> {
112    list: &'a List<T>,
113    range: Range<u32>
114}
115
116impl<'a, T> ListIter<'a, T> {
117    /// Returns a new instance of Iter.
118    fn new(list: &'a List<T>) -> Self {
119        Self {
120            list,
121            range: Range {
122                start: 0,
123                end: list.len()
124            }
125        }
126    }
127
128    /// Returns number of elements left to iterate.
129    fn remaining(&self) -> usize {
130        (self.range.end - self.range.start) as usize
131    }
132}
133
134impl<T> core::iter::Iterator for ListIter<'_, T>
135where
136    T: ToBytes + FromBytes + CLTyped
137{
138    type Item = T;
139
140    fn next(&mut self) -> Option<Self::Item> {
141        <Self as Iterator>::nth(self, 0)
142    }
143
144    fn size_hint(&self) -> (usize, Option<usize>) {
145        let remaining = self.remaining();
146        (remaining, Some(remaining))
147    }
148
149    fn count(self) -> usize {
150        self.remaining()
151    }
152
153    fn nth(&mut self, n: usize) -> Option<Self::Item> {
154        let index = self.range.nth(n)?;
155        self.list.get(index)
156    }
157}
158
159impl<T> core::iter::ExactSizeIterator for ListIter<'_, T> where T: ToBytes + FromBytes + CLTyped {}
160
161impl<T> core::iter::FusedIterator for ListIter<'_, T> where T: ToBytes + FromBytes + CLTyped {}
162
163impl<T> core::iter::DoubleEndedIterator for ListIter<'_, T>
164where
165    T: ToBytes + FromBytes + CLTyped
166{
167    fn next_back(&mut self) -> Option<Self::Item> {
168        let index = self.range.nth_back(0)?;
169        self.list.get(index)
170    }
171}
172
173impl<T: ToBytes + FromBytes + CLTyped + Default> List<T> {
174    /// Reads `key` from the storage or the default value is returned.
175    pub fn get_or_default(&self, index: u32) -> T {
176        self.get(index).unwrap_or_default()
177    }
178}