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::{borrow::Borrow, cmp::Ordering, marker::PhantomData};
9
10const MAP_OOB: Error = Error::from_type_and_code(ScErrorType::Object, ScErrorCode::IndexBounds);
11
12pub struct MeteredOrdMap<K, V, Ctx> {
13 pub(crate) map: Vec<(K, V)>,
14 ctx: PhantomData<Ctx>,
15}
16
17impl<K, V, Ctx> Clone for MeteredOrdMap<K, V, Ctx>
20where
21 K: MeteredClone,
22 V: MeteredClone,
23 Ctx: AsBudget,
24{
25 fn clone(&self) -> Self {
26 Self {
27 map: self.map.clone(),
28 ctx: Default::default(),
29 }
30 }
31}
32
33impl<K, V, Ctx> std::hash::Hash for MeteredOrdMap<K, V, Ctx>
34where
35 K: std::hash::Hash,
36 V: std::hash::Hash,
37{
38 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
39 self.map.hash(state);
40 }
41}
42
43impl<K, V, Ctx> MeteredOrdMap<K, V, Ctx>
44where
45 K: DeclaredSizeForMetering,
46 V: DeclaredSizeForMetering,
47 Ctx: AsBudget,
48{
49 const ENTRY_SIZE: u64 = <(K, V) as DeclaredSizeForMetering>::DECLARED_SIZE;
50
51 fn charge_access<B: AsBudget>(&self, count: usize, b: &B) -> Result<(), HostError> {
52 b.as_budget().charge(
53 ContractCostType::MemCpy,
54 Some(Self::ENTRY_SIZE.saturating_mul(count as u64)),
55 )
56 }
57
58 fn charge_scan<B: AsBudget>(&self, b: &B) -> Result<(), HostError> {
59 Self::charge_access(self, self.map.len(), b)
60 }
61
62 fn charge_binsearch<B: AsBudget>(&self, b: &B) -> Result<(), HostError> {
66 let mag: u32 = 64u32.saturating_sub((self.map.len() as u64).leading_zeros());
67 b.as_budget().charge(
68 ContractCostType::MemCpy,
69 Some(Self::ENTRY_SIZE.saturating_mul(mag.saturating_add(1u32) as u64)),
70 )
71 }
72}
73
74impl<K, V, Ctx> Default for MeteredOrdMap<K, V, Ctx>
75where
76 Ctx: Default,
77{
78 fn default() -> Self {
79 Self {
80 map: Default::default(),
81 ctx: Default::default(),
82 }
83 }
84}
85
86impl<K, V, Ctx> MeteredOrdMap<K, V, Ctx>
93where
94 K: MeteredClone,
95 V: MeteredClone,
96 Ctx: AsBudget + Compare<K, Error = HostError>,
97{
98 pub fn new() -> Self {
99 MeteredOrdMap {
100 map: Vec::new(),
101 ctx: Default::default(),
102 }
103 }
104
105 pub fn from_map(map: Vec<(K, V)>, ctx: &Ctx) -> Result<Self, HostError> {
106 if u32::try_from(map.len()).is_err() {
107 return Err(MAP_OOB.into());
108 }
109 let m = MeteredOrdMap {
112 map,
113 ctx: Default::default(),
114 };
115 m.charge_scan(ctx)?;
116 for w in m.map.as_slice().windows(2) {
117 let [a, b] = w else {
118 return Err((ScErrorType::Object, ScErrorCode::InternalError).into());
119 };
120 match <Ctx as Compare<K>>::compare(ctx, &a.0, &b.0)? {
121 Ordering::Less => (),
122 _ => return Err((ScErrorType::Object, ScErrorCode::InvalidInput).into()),
123 }
124 }
125 Ok(m)
126 }
127
128 pub fn from_exact_iter<I: Iterator<Item = (K, V)>>(
133 iter: I,
134 ctx: &Ctx,
135 ) -> Result<Self, HostError> {
136 let _span = tracy_span!("new map");
137 if let (_, Some(sz)) = iter.size_hint() {
138 if u32::try_from(sz).is_err() {
139 Err(MAP_OOB.into())
140 } else {
141 let map: Vec<(K, V)> = iter.collect();
146 map.charge_deep_clone(ctx.as_budget())?;
147 Self::from_map(map, ctx)
149 }
150 } else {
151 Err((ScErrorType::Object, ScErrorCode::InternalError).into())
153 }
154 }
155
156 fn find<Q>(&self, key: &Q, ctx: &Ctx) -> Result<Result<usize, usize>, HostError>
157 where
158 K: Borrow<Q>,
159 Ctx: Compare<Q, Error = HostError>,
160 {
161 let _span = tracy_span!("map lookup");
162 self.charge_binsearch(ctx)?;
163 let mut err: Option<HostError> = None;
164 let res = self.map.binary_search_by(|probe| {
165 if err.is_some() {
168 return Ordering::Equal;
169 }
170 match <Ctx as Compare<Q>>::compare(ctx, probe.0.borrow(), key) {
171 Ok(ord) => ord,
172 Err(he) => {
173 err = Some(he);
174 Ordering::Equal
175 }
176 }
177 });
178 match err {
179 Some(he) => Err(he),
180 None => Ok(res),
181 }
182 }
183
184 pub fn insert(&self, key: K, value: V, ctx: &Ctx) -> Result<Self, HostError> {
185 self.charge_access(1, ctx)?;
186 match self.find(&key, ctx)? {
187 Ok(replace_pos) => {
188 if replace_pos == usize::MAX - 1 {
192 return Err(MAP_OOB.into());
193 }
194 let init = self.map.iter().take(replace_pos).cloned();
195 let fini = self.map.iter().skip(replace_pos.saturating_add(1)).cloned();
196 let iter = init.chain([(key, value)]).chain(fini);
197 Self::from_exact_iter(iter, ctx)
198 }
199 Err(insert_pos) => {
200 if self.len() == u32::MAX as usize {
204 return Err(MAP_OOB.into());
205 } else {
206 let init = self.map.iter().take(insert_pos).cloned();
207 let fini = self.map.iter().skip(insert_pos).cloned();
208 let iter = init.chain([(key, value)]).chain(fini);
209 Self::from_exact_iter(iter, ctx)
210 }
211 }
212 }
213 }
214
215 pub fn get<Q>(&self, key: &Q, ctx: &Ctx) -> Result<Option<&V>, HostError>
216 where
217 K: Borrow<Q>,
218 Ctx: Compare<Q, Error = HostError>,
219 {
220 match self.find(key, ctx)? {
221 Ok(found) => {
222 self.charge_access(1, ctx)?;
223 let Some((_, v)) = self.map.get(found) else {
224 return Err((ScErrorType::Object, ScErrorCode::InternalError).into());
225 };
226 Ok(Some(v))
227 }
228 _ => Ok(None),
229 }
230 }
231
232 pub fn get_at_index(&self, index: usize, ctx: &Ctx) -> Result<&(K, V), HostError> {
233 self.charge_access(1, ctx)?;
234 self.map.get(index).ok_or_else(|| {
235 Error::from_type_and_code(ScErrorType::Object, ScErrorCode::IndexBounds).into()
236 })
237 }
238
239 pub fn remove<Q>(&self, key: &Q, ctx: &Ctx) -> Result<Option<(Self, V)>, HostError>
243 where
244 K: Borrow<Q>,
245 Ctx: Compare<Q, Error = HostError>,
246 {
247 match self.find(key, ctx)? {
248 Ok(found) if found > 0 => {
249 let init = self.map.iter().take(found).cloned();
256 let fini = self.map.iter().skip(found.saturating_add(1)).cloned();
257 let iter = init.chain(fini);
258 let new = Self::from_exact_iter(iter, ctx)?;
259 let Some((_, res)) = self.map.get(found) else {
260 return Err((ScErrorType::Object, ScErrorCode::InternalError).into());
261 };
262 Ok(Some((new, res.metered_clone(ctx.as_budget())?)))
263 }
264 Ok(found) => {
265 let iter = self.map.iter().skip(1).cloned();
268 let new = Self::from_exact_iter(iter, ctx)?;
269 let Some((_, res)) = self.map.get(found) else {
270 return Err((ScErrorType::Object, ScErrorCode::InternalError).into());
271 };
272 Ok(Some((new, res.metered_clone(ctx.as_budget())?)))
273 }
274 _ => Ok(None),
275 }
276 }
277
278 pub fn len(&self) -> usize {
279 self.map.len()
280 }
281
282 pub fn contains_key<Q>(&self, key: &Q, ctx: &Ctx) -> Result<bool, HostError>
283 where
284 K: Borrow<Q>,
285 Ctx: Compare<Q, Error = HostError>,
286 {
287 Ok(self.find(key, ctx)?.is_ok())
288 }
289
290 pub fn keys(&self, ctx: &Ctx) -> Result<impl Iterator<Item = &K>, HostError> {
291 self.charge_scan(ctx)?;
292 Ok(self.map.iter().map(|(k, _)| k))
293 }
294
295 pub fn values(&self, ctx: &Ctx) -> Result<impl Iterator<Item = &V>, HostError> {
296 self.charge_scan(ctx)?;
297 Ok(self.map.iter().map(|(_, v)| v))
298 }
299
300 pub fn iter(&self, ctx: &Ctx) -> Result<impl Iterator<Item = &(K, V)>, HostError> {
301 self.charge_scan(ctx)?;
302 Ok(self.map.iter())
303 }
304}
305
306impl<K, V, Ctx> DeclaredSizeForMetering for MeteredOrdMap<K, V, Ctx>
307where
308 K: DeclaredSizeForMetering,
309 V: DeclaredSizeForMetering,
310{
311 const DECLARED_SIZE: u64 = <Vec<(K, V)> as DeclaredSizeForMetering>::DECLARED_SIZE;
312}
313
314impl<K, V, Ctx> MeteredClone for MeteredOrdMap<K, V, Ctx>
315where
316 K: MeteredClone,
317 V: MeteredClone,
318 Ctx: AsBudget,
319{
320 fn charge_for_substructure(&self, budget: impl AsBudget) -> Result<(), HostError> {
321 self.map.charge_for_substructure(budget)
322 }
323}
324
325impl<K, V> Compare<MeteredOrdMap<K, V, Host>> for Host
326where
327 K: DeclaredSizeForMetering,
328 V: DeclaredSizeForMetering,
329 Host: Compare<K, Error = HostError> + Compare<V, Error = HostError>,
330{
331 type Error = HostError;
332
333 fn compare(
334 &self,
335 a: &MeteredOrdMap<K, V, Host>,
336 b: &MeteredOrdMap<K, V, Host>,
337 ) -> Result<Ordering, Self::Error> {
338 self.as_budget().charge(
341 ContractCostType::MemCpy,
342 Some(
343 <(K, V) as DeclaredSizeForMetering>::DECLARED_SIZE
344 .saturating_mul(a.map.len().min(b.map.len()) as u64),
345 ),
346 )?;
347 <Self as Compare<Vec<(K, V)>>>::compare(self, &a.map, &b.map)
348 }
349}
350
351impl<K, V> Compare<MeteredOrdMap<K, V, Budget>> for Budget
352where
353 K: DeclaredSizeForMetering,
354 V: DeclaredSizeForMetering,
355 Budget: Compare<K, Error = HostError> + Compare<V, Error = HostError>,
356{
357 type Error = HostError;
358
359 fn compare(
360 &self,
361 a: &MeteredOrdMap<K, V, Budget>,
362 b: &MeteredOrdMap<K, V, Budget>,
363 ) -> Result<Ordering, Self::Error> {
364 self.charge(
367 ContractCostType::MemCpy,
368 Some(
369 <(K, V) as DeclaredSizeForMetering>::DECLARED_SIZE
370 .saturating_mul(a.map.len().min(b.map.len()) as u64),
371 ),
372 )?;
373 <Self as Compare<Vec<(K, V)>>>::compare(self, &a.map, &b.map)
374 }
375}
376
377impl<'a, K, V, Ctx> IntoIterator for &'a MeteredOrdMap<K, V, Ctx> {
378 type Item = &'a (K, V);
379 type IntoIter = core::slice::Iter<'a, (K, V)>;
380
381 fn into_iter(self) -> Self::IntoIter {
382 self.map.iter()
383 }
384}
385
386impl<K, V, Ctx> IntoIterator for MeteredOrdMap<K, V, Ctx> {
387 type Item = (K, V);
388 type IntoIter = std::vec::IntoIter<(K, V)>;
389
390 fn into_iter(self) -> Self::IntoIter {
391 self.map.into_iter()
392 }
393}