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