1use crate::{
2 budget::{AsBudget, Budget},
3 host::{declared_size::DeclaredSizeForMetering, MeteredClone},
4 xdr::{ContractCostType, ScErrorCode, ScErrorType},
5 Compare, Error, Host, HostError,
6};
7
8use std::{cmp::Ordering, ops::Range};
9
10const VEC_OOB: Error = Error::from_type_and_code(ScErrorType::Object, ScErrorCode::IndexBounds);
11
12#[derive(Clone)]
13pub struct MeteredVector<A> {
14 pub(crate) vec: Vec<A>,
15}
16
17impl<A> Default for MeteredVector<A> {
18 fn default() -> Self {
19 Self {
20 vec: Default::default(),
21 }
22 }
23}
24
25impl<T> std::hash::Hash for MeteredVector<T>
26where
27 T: std::hash::Hash,
28{
29 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
30 self.vec.hash(state);
31 }
32}
33
34impl<A> MeteredVector<A>
35where
36 A: DeclaredSizeForMetering,
37{
38 fn charge_access(&self, count: usize, budget: &Budget) -> Result<(), HostError> {
39 budget.charge(
40 ContractCostType::MemCpy,
41 Some(A::DECLARED_SIZE.saturating_mul(count as u64)),
42 )
43 }
44
45 fn charge_scan(&self, budget: &Budget) -> Result<(), HostError> {
46 budget.charge(
47 ContractCostType::MemCpy,
48 Some(A::DECLARED_SIZE.saturating_mul(self.vec.len() as u64)),
49 )
50 }
51
52 fn charge_binsearch(&self, budget: &Budget) -> Result<(), HostError> {
55 let mag = 64u32.saturating_sub((self.vec.len() as u64).leading_zeros());
56 budget.charge(
57 ContractCostType::MemCpy,
58 Some(A::DECLARED_SIZE.saturating_mul((1 + mag) as u64)),
59 )
60 }
61}
62
63impl<A> MeteredVector<A>
64where
65 A: MeteredClone,
66{
67 pub fn new() -> Self {
69 Self { vec: Vec::new() }
70 }
71
72 #[cfg(feature = "bench")]
77 pub fn with_capacity(capacity: usize, budget: &Budget) -> Result<Self, HostError> {
78 super::metered_clone::charge_heap_alloc::<A>(capacity as u64, budget)?;
79 Self::from_vec(Vec::with_capacity(capacity))
80 }
81
82 pub fn from_vec(vec: Vec<A>) -> Result<Self, HostError> {
84 if u32::try_from(vec.len()).is_err() {
85 Err(VEC_OOB.into())
86 } else {
87 Ok(Self { vec })
88 }
89 }
90
91 pub fn as_slice(&self) -> &[A] {
92 self.vec.as_slice()
93 }
94
95 pub fn as_mut_slice(&mut self) -> &mut [A] {
96 self.vec.as_mut_slice()
97 }
98
99 pub fn from_exact_iter<I: Iterator<Item = A>>(
104 iter: I,
105 budget: &Budget,
106 ) -> Result<Self, HostError> {
107 let _span = tracy_span!("new vec");
108 if let (_, Some(sz)) = iter.size_hint() {
109 if u32::try_from(sz).is_err() {
110 Err(VEC_OOB.into())
111 } else {
112 let vec: Vec<A> = iter.collect();
117 vec.charge_deep_clone(budget)?;
118 Self::from_vec(vec)
119 }
120 } else {
121 Err((ScErrorType::Object, ScErrorCode::InternalError).into())
123 }
124 }
125
126 pub fn set(&self, index: usize, value: A, budget: &Budget) -> Result<Self, HostError> {
127 let mut new = self.metered_clone(budget)?;
128 new.charge_access(1, budget)?;
129 let cell: Result<&mut A, HostError> = new.vec.get_mut(index).ok_or_else(|| VEC_OOB.into());
130 *(cell?) = value;
131 Ok(new)
132 }
133
134 pub fn get(&self, index: usize, budget: &Budget) -> Result<&A, HostError> {
135 self.charge_access(1, budget)?;
136 self.vec.get(index).ok_or_else(|| VEC_OOB.into())
137 }
138
139 pub fn len(&self) -> usize {
140 self.vec.len()
141 }
142
143 pub fn push_front(&self, value: A, budget: &Budget) -> Result<Self, HostError> {
144 if self.len() == u32::MAX as usize {
145 Err(VEC_OOB.into())
146 } else {
147 let iter = [value].into_iter().chain(self.vec.iter().cloned());
148 Self::from_exact_iter(iter, budget)
149 }
150 }
151
152 pub fn pop_front(&self, budget: &Budget) -> Result<Self, HostError> {
153 if self.vec.is_empty() {
154 Err(VEC_OOB.into())
155 } else {
156 let iter = self.vec.iter().skip(1).cloned();
157 Self::from_exact_iter(iter, budget)
158 }
159 }
160
161 pub fn push_back(&self, value: A, budget: &Budget) -> Result<Self, HostError> {
162 if self.len() == u32::MAX as usize {
163 Err(VEC_OOB.into())
164 } else {
165 let iter = self.vec.iter().cloned().chain([value]);
166 Self::from_exact_iter(iter, budget)
167 }
168 }
169
170 fn err_oob() -> HostError {
171 VEC_OOB.into()
172 }
173
174 fn add_or_err(x: usize, y: usize) -> Result<usize, HostError> {
175 let sz = x.checked_add(y).ok_or_else(|| Self::err_oob())?;
176 if u32::try_from(sz).is_err() {
177 Err(Self::err_oob())
178 } else {
179 Ok(sz)
180 }
181 }
182
183 fn sub_or_err(x: usize, y: usize) -> Result<usize, HostError> {
184 x.checked_sub(y).ok_or_else(|| Self::err_oob())
185 }
186
187 pub fn pop_back(&self, budget: &Budget) -> Result<Self, HostError> {
188 if self.vec.is_empty() {
189 Err(VEC_OOB.into())
190 } else {
191 let count = Self::sub_or_err(self.vec.len(), 1)?;
192 let iter = self.vec.iter().take(count).cloned();
193 Self::from_exact_iter(iter, budget)
194 }
195 }
196
197 pub fn remove(&self, idx: usize, budget: &Budget) -> Result<Self, HostError> {
198 if idx >= self.vec.len() || idx == usize::MAX - 1 {
199 Err(VEC_OOB.into())
200 } else {
201 let skip = Self::add_or_err(idx, 1)?;
204 let init = self.vec.iter().take(idx).cloned();
205 let fini = self.vec.iter().skip(skip).cloned();
206 Self::from_exact_iter(init.chain(fini), budget)
207 }
208 }
209
210 pub fn front(&self, budget: &Budget) -> Result<&A, HostError> {
211 self.charge_access(1, budget)?;
212 self.vec.first().ok_or_else(|| VEC_OOB.into())
213 }
214
215 pub fn back(&self, budget: &Budget) -> Result<&A, HostError> {
216 self.charge_access(1, budget)?;
217 self.vec.last().ok_or_else(|| VEC_OOB.into())
218 }
219
220 pub fn insert(&self, index: usize, value: A, budget: &Budget) -> Result<Self, HostError> {
221 if self.vec.len() == u32::MAX as usize {
222 return Err(VEC_OOB.into());
223 }
224 let len = self.vec.len();
225 if index > len {
226 Err(VEC_OOB.into())
227 } else if index == len {
228 self.push_back(value, budget)
229 } else if index == 0 {
230 self.push_front(value, budget)
231 } else {
232 let init = self.vec.iter().take(index).cloned();
233 let fini = self.vec.iter().skip(index).cloned();
234 let iter = init.chain([value]).chain(fini);
235 Self::from_exact_iter(iter, budget)
236 }
237 }
238
239 pub fn append(&self, other: &Self, budget: &Budget) -> Result<Self, HostError> {
240 Self::add_or_err(self.len(), other.len())?;
241 let iter = self.vec.iter().cloned().chain(other.vec.iter().cloned());
242 Self::from_exact_iter(iter, budget)
243 }
244
245 pub fn slice(&self, range: Range<usize>, budget: &Budget) -> Result<Self, HostError> {
246 match self.vec.get(range) {
247 Some(slice) => Self::from_exact_iter(slice.iter().cloned(), budget),
248 None => Err(VEC_OOB.into()),
249 }
250 }
251
252 pub fn first_index_of<F>(&self, f: F, budget: &Budget) -> Result<Option<usize>, HostError>
253 where
254 F: Fn(&A) -> Result<Ordering, HostError>,
255 {
256 self.charge_scan(budget)?;
257 for (i, val) in self.vec.iter().enumerate() {
259 if f(val)? == Ordering::Equal {
260 return Ok(Some(i));
261 }
262 }
263 Ok(None)
264 }
265
266 pub fn last_index_of<F>(&self, f: F, budget: &Budget) -> Result<Option<usize>, HostError>
267 where
268 F: Fn(&A) -> Result<Ordering, HostError>,
269 {
270 self.charge_scan(budget)?;
271 for (i, val) in self.vec.iter().enumerate().rev() {
273 if f(val)? == Ordering::Equal {
274 return Ok(Some(i));
275 }
276 }
277 Ok(None)
278 }
279
280 pub fn binary_search_by<F>(
281 &self,
282 mut cmp: F,
283 budget: &Budget,
284 ) -> Result<Result<usize, usize>, HostError>
285 where
286 F: FnMut(&A) -> Result<Ordering, HostError>,
287 {
288 self.charge_binsearch(budget)?;
289 let mut err: Option<HostError> = None;
290 let res = binary_search_by_pre_rust_182(self.vec.as_slice(), |probe| {
291 if err.is_some() {
294 return Ordering::Equal;
295 }
296 match cmp(probe) {
297 Ok(ord) => ord,
298 Err(he) => {
299 err = Some(he);
300 Ordering::Equal
301 }
302 }
303 });
304 match err {
305 Some(he) => Err(he),
306 None => Ok(res),
307 }
308 }
309
310 pub fn iter(&self) -> std::slice::Iter<'_, A> {
311 self.vec.iter()
312 }
313
314 pub fn to_vec(&self, budget: &Budget) -> Result<Vec<A>, HostError> {
315 self.vec.metered_clone(budget)
316 }
317}
318
319impl<A> DeclaredSizeForMetering for MeteredVector<A>
320where
321 A: DeclaredSizeForMetering,
322{
323 const DECLARED_SIZE: u64 = <Vec<A> as DeclaredSizeForMetering>::DECLARED_SIZE;
324}
325
326impl<A> MeteredClone for MeteredVector<A>
327where
328 A: MeteredClone,
329{
330 fn charge_for_substructure(&self, budget: impl AsBudget) -> Result<(), HostError> {
331 self.vec.charge_for_substructure(budget)
332 }
333}
334
335impl<Elt: MeteredClone> Compare<MeteredVector<Elt>> for Budget
336where
337 Budget: Compare<Elt, Error = HostError>,
338{
339 type Error = HostError;
340
341 fn compare(
342 &self,
343 a: &MeteredVector<Elt>,
344 b: &MeteredVector<Elt>,
345 ) -> Result<Ordering, Self::Error> {
346 self.as_budget().charge(
349 ContractCostType::MemCpy,
350 Some(Elt::DECLARED_SIZE.saturating_mul(a.vec.len().min(b.vec.len()) as u64)),
351 )?;
352 <Self as Compare<Vec<Elt>>>::compare(self, &a.vec, &b.vec)
353 }
354}
355
356impl<Elt: MeteredClone> Compare<MeteredVector<Elt>> for Host
357where
358 Host: Compare<Elt, Error = HostError>,
359{
360 type Error = HostError;
361
362 fn compare(
363 &self,
364 a: &MeteredVector<Elt>,
365 b: &MeteredVector<Elt>,
366 ) -> Result<Ordering, Self::Error> {
367 self.as_budget().charge(
370 ContractCostType::MemCpy,
371 Some(Elt::DECLARED_SIZE.saturating_mul(a.vec.len().min(b.vec.len()) as u64)),
372 )?;
373 <Self as Compare<Vec<Elt>>>::compare(self, &a.vec, &b.vec)
374 }
375}
376
377pub(crate) fn binary_search_by_pre_rust_182<F, T>(slice: &[T], mut f: F) -> Result<usize, usize>
389where
390 F: FnMut(&T) -> std::cmp::Ordering,
391{
392 let mut size = slice.len();
397 let mut left = 0;
398 let mut right = size;
399 while left < right {
400 let mid = left + size / 2;
401
402 let cmp = f(slice.get(mid).unwrap());
407
408 left = if cmp == std::cmp::Ordering::Less {
413 mid + 1
414 } else {
415 left
416 };
417 right = if cmp == std::cmp::Ordering::Greater {
418 mid
419 } else {
420 right
421 };
422 if cmp == std::cmp::Ordering::Equal {
423 return Ok(mid);
424 }
425
426 size = right - left;
427 }
428 Err(left)
429}