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
15pub 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 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 pub fn is_empty(&self) -> bool {
52 self.len() == 0
53 }
54
55 pub fn len(&self) -> u32 {
57 self.current_index.get_or_default()
58 }
59}
60
61impl<T: FromBytes + CLTyped> List<T> {
62 pub fn get(&self, index: u32) -> Option<T> {
64 self.values.get(&index)
65 }
66}
67
68impl<T: ToBytes + FromBytes + CLTyped> List<T> {
69 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 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 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 pub fn iter(&self) -> ListIter<T> {
101 ListIter::new(self)
102 }
103}
104
105pub struct ListIter<'a, T> {
112 list: &'a List<T>,
113 range: Range<u32>
114}
115
116impl<'a, T> ListIter<'a, T> {
117 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 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 pub fn get_or_default(&self, index: u32) -> T {
176 self.get(index).unwrap_or_default()
177 }
178}