1use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
5use std::fmt::{self, Write};
6use std::hash::Hash;
7
8use crate::CodecError;
9
10use super::{
11 u64_from_index, BoundedCount, DecodeContext, ResourceDimension, ResourceLimit,
12 ScopedReservation,
13};
14
15#[derive(Debug)]
17pub struct ExactVec<T> {
18 values: Vec<T>,
19 capacity: usize,
20}
21
22impl<T> ExactVec<T> {
23 pub fn new(
25 ctx: &DecodeContext<'_>,
26 count: BoundedCount,
27 operation: &'static str,
28 ) -> Result<Self, CodecError> {
29 let capacity = count.get();
30 let values = ctx.collection_vec(capacity, operation)?;
31 Ok(Self { values, capacity })
32 }
33
34 pub fn push(&mut self, value: T) -> Result<(), CodecError> {
36 if self.values.len() == self.capacity {
37 return Err(CodecError::Malformed(
38 "fixed-capacity vector overflow".to_owned(),
39 ));
40 }
41 self.values.push(value);
42 Ok(())
43 }
44
45 pub fn finish(self) -> Result<Vec<T>, CodecError> {
47 if self.values.len() == self.capacity {
48 Ok(self.values)
49 } else {
50 Err(CodecError::malformed(format_args!(
51 "fixed-capacity vector contains {} of {} values",
52 self.values.len(),
53 self.capacity
54 )))
55 }
56 }
57}
58
59#[derive(Clone, Copy)]
60enum VecGrowth {
61 Exact,
62 Amortized,
63}
64
65impl DecodeContext<'_> {
66 pub fn reserve_capacity_limit<T>(
68 &self,
69 values: &mut Vec<T>,
70 count: usize,
71 operation: &'static str,
72 ) -> Result<(), ResourceLimit> {
73 self.reserve_retained_vec_storage(values, count, VecGrowth::Amortized, None, operation)
74 }
75
76 fn reserve_retained_vec_storage<T>(
77 &self,
78 values: &mut Vec<T>,
79 count: usize,
80 growth: VecGrowth,
81 items: Option<usize>,
82 operation: &'static str,
83 ) -> Result<(), ResourceLimit> {
84 let required = values
85 .len()
86 .checked_add(count)
87 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
88 let capacity = if std::mem::size_of::<T>() == 0 || required <= values.capacity() {
89 values.capacity()
90 } else if matches!(growth, VecGrowth::Exact) {
91 required
92 } else if values.capacity() == 0 {
93 let minimum = match std::mem::size_of::<T>() {
94 1 => 8,
95 2..=1024 => 4,
96 _ => 1,
97 };
98 required.max(minimum)
99 } else {
100 match values.capacity().checked_mul(2) {
101 Some(grown) if grown > required => grown,
102 _ => required,
103 }
104 };
105 let added = capacity - values.capacity();
106 let bytes = added
107 .checked_mul(std::mem::size_of::<T>())
108 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
109 let maximum = usize::try_from(isize::MAX)
110 .map_err(|_| self.retained_size_overflow_limit(operation))?;
111 if bytes > maximum {
112 return Err(self
113 .budget
114 .retained_allocation_failed_limit(u64_from_index(bytes), operation));
115 }
116 self.charge_retained_limit(u64_from_index(bytes), operation)?;
117 if let Some(items) = items {
118 self.charge_collection_items_limit(u64_from_index(items), operation)?;
119 }
120 if added != 0 {
121 values
122 .try_reserve_exact(capacity - values.len())
123 .map_err(|_| {
124 self.budget
125 .retained_allocation_failed_limit(u64_from_index(bytes), operation)
126 })?;
127 }
128 Ok(())
129 }
130
131 pub fn reserve_capacity<T>(
133 &self,
134 values: &mut Vec<T>,
135 count: usize,
136 operation: &'static str,
137 ) -> Result<(), CodecError> {
138 self.reserve_retained_vec_storage(values, count, VecGrowth::Amortized, None, operation)
139 .map_err(Into::into)
140 }
141
142 pub fn vector_storage<T>(
144 &self,
145 count: usize,
146 operation: &'static str,
147 ) -> Result<Vec<T>, CodecError> {
148 let mut values = Vec::new();
149 self.reserve_retained_vec_storage(&mut values, count, VecGrowth::Exact, None, operation)?;
150 Ok(values)
151 }
152
153 pub fn reserve_scoped_collection<T>(
155 &self,
156 count: usize,
157 operation: &'static str,
158 ) -> Result<ScopedReservation<'_>, CodecError> {
159 self.charge_collection_items(u64_from_index(count), operation)?;
160 let bytes = count
161 .checked_mul(std::mem::size_of::<T>())
162 .ok_or_else(|| self.budget.scoped_size_overflow_limit(operation))?;
163 self.reserve_scoped(u64_from_index(bytes), operation)
164 }
165
166 pub fn scoped_vector_storage<T>(
168 &self,
169 count: usize,
170 operation: &'static str,
171 ) -> Result<(Vec<T>, ScopedReservation<'_>), CodecError> {
172 let mut reservation = self.reserve_scoped(0, operation)?;
173 let values = reservation.with_storage(|| self.vector_storage(count, operation))?;
174 Ok((values, reservation))
175 }
176
177 pub fn reserve_scoped_vec<T>(
179 &self,
180 reservation: &mut ScopedReservation<'_>,
181 values: &mut Vec<T>,
182 count: usize,
183 operation: &'static str,
184 ) -> Result<(), CodecError> {
185 self.reserve_scoped_vec_limit(reservation, values, count, operation)
186 .map_err(Into::into)
187 }
188
189 pub fn reserve_scoped_vec_limit<T>(
191 &self,
192 reservation: &mut ScopedReservation<'_>,
193 values: &mut Vec<T>,
194 count: usize,
195 operation: &'static str,
196 ) -> Result<(), ResourceLimit> {
197 reservation.with_storage_limit(|| self.reserve_vec_limit(values, count, operation))
198 }
199
200 pub fn push_scoped_vec<T>(
202 &self,
203 reservation: &mut ScopedReservation<'_>,
204 values: &mut Vec<T>,
205 value: T,
206 operation: &'static str,
207 ) -> Result<(), CodecError> {
208 self.reserve_scoped_vec(reservation, values, 1, operation)?;
209 values.push(value);
210 Ok(())
211 }
212
213 pub fn reserve_temporary_vec<T>(
215 &self,
216 values: &mut Vec<T>,
217 count: usize,
218 operation: &'static str,
219 ) -> Result<ScopedReservation<'_>, ResourceLimit> {
220 let mut reservation = self.reserve_scoped_limit(0, operation)?;
221 reservation.with_storage_limit(|| {
222 self.reserve_retained_vec_storage(
223 values,
224 count,
225 VecGrowth::Exact,
226 Some(count),
227 operation,
228 )
229 })?;
230 Ok(reservation)
231 }
232
233 pub fn copy_temporary_slice<T: Copy>(
235 &self,
236 values: &[T],
237 operation: &'static str,
238 ) -> Result<(Vec<T>, ScopedReservation<'_>), ResourceLimit> {
239 let mut copy = Vec::new();
240 let reservation = self.reserve_temporary_vec(&mut copy, values.len(), operation)?;
241 self.charge_work_limit(u64_from_index(values.len()), operation)?;
242 copy.extend_from_slice(values);
243 Ok((copy, reservation))
244 }
245
246 pub fn collect_retained_texts<'text>(
248 &self,
249 values: impl IntoIterator<Item = &'text str>,
250 operation: &'static str,
251 ) -> Result<Vec<String>, CodecError> {
252 self.try_collect_retained_with(values, operation, |value| {
253 self.copy_retained_text(value, operation)
254 })
255 }
256
257 pub fn collect_scoped_texts<'text>(
259 &self,
260 values: impl IntoIterator<Item = &'text str>,
261 operation: &'static str,
262 ) -> Result<(Vec<String>, ScopedReservation<'_>), CodecError> {
263 let mut reservation = self.reserve_scoped(0, operation)?;
264 let copies = reservation.with_storage(|| self.collect_retained_texts(values, operation))?;
265 Ok((copies, reservation))
266 }
267
268 pub fn format_scoped_text(
270 &self,
271 reservation: &mut ScopedReservation<'_>,
272 args: fmt::Arguments<'_>,
273 operation: &'static str,
274 ) -> Result<String, CodecError> {
275 reservation.with_storage(|| self.format_retained(args, operation))
276 }
277
278 pub fn reserve_record_vec<T>(
280 &self,
281 records: &mut Vec<T>,
282 count: usize,
283 text_bytes: u64,
284 operation: &'static str,
285 ) -> Result<(), CodecError> {
286 self.charge_entities(u64_from_index(count), operation)?;
287 self.charge_retained(text_bytes, operation)?;
288 self.reserve_vec(records, count, operation)
289 }
290
291 pub fn collect_retained_vec<T>(
293 &self,
294 values: impl IntoIterator<Item = T>,
295 operation: &'static str,
296 ) -> Result<Vec<T>, CodecError> {
297 self.try_collect_retained_with(values, operation, Ok::<T, CodecError>)
298 }
299
300 pub(crate) fn reserve_admitted_string(
302 text: &mut String,
303 additional: usize,
304 operation: &'static str,
305 ) -> Result<(), CodecError> {
306 text.try_reserve_exact(additional).map_err(|_| {
307 CodecError::ResourceLimit(ResourceLimit::allocation_failed(
308 ResourceDimension::RetainedBytes,
309 u64::MAX,
310 u64_from_index(additional),
311 operation,
312 ))
313 })
314 }
315
316 pub fn charge_btree_lookup(
318 &self,
319 len: usize,
320 operation: &'static str,
321 ) -> Result<(), CodecError> {
322 let mut levels = 1_u64;
327 let mut minimum_subtree = len.div_ceil(2);
328 while minimum_subtree >= 6 {
329 minimum_subtree /= 6;
330 levels += 1;
331 }
332 self.charge_work(u64_from_index(len).min(11 * levels), operation)
333 }
334
335 pub fn insert_scoped_btree_set<T: Ord>(
337 &self,
338 reservation: &mut ScopedReservation<'_>,
339 values: &mut BTreeSet<T>,
340 value: T,
341 work_operation: &'static str,
342 operation: &'static str,
343 ) -> Result<bool, CodecError> {
344 self.charge_btree_lookup(values.len(), work_operation)?;
345 if values.contains(&value) {
346 return Ok(false);
347 }
348 self.charge_btree_lookup(values.len(), work_operation)?;
350 reservation.with_storage(|| {
351 self.charge_retained(
352 self.tree_growth_bytes::<T, ()>(values.len(), operation)?,
353 operation,
354 )?;
355 self.charge_collection_items(1, operation)?;
356 Ok(values.insert(value))
357 })
358 }
359
360 pub fn insert_scoped_btree_map_if_vacant<K: Ord, V>(
362 &self,
363 reservation: &mut ScopedReservation<'_>,
364 values: &mut BTreeMap<K, V>,
365 key: K,
366 value: V,
367 work_operation: &'static str,
368 operation: &'static str,
369 ) -> Result<bool, CodecError> {
370 self.charge_work(u64_from_index(values.len()), work_operation)?;
371 reservation.with_storage(|| {
372 if values.contains_key(&key) {
373 return Ok(false);
374 }
375 self.insert_btree_map(values, key, value, operation)?;
376 Ok(true)
377 })
378 }
379
380 pub fn push_scoped_btree_group<K: Ord, V>(
382 &self,
383 reservation: &mut ScopedReservation<'_>,
384 groups: &mut BTreeMap<K, Vec<V>>,
385 key: K,
386 value: impl FnOnce() -> V,
387 owned_bytes: usize,
388 operation: &'static str,
389 ) -> Result<(), CodecError> {
390 self.charge_work(u64_from_index(groups.len()) + 1, operation)?;
391 reservation.with_storage(|| {
392 if let Some(values) = groups.get_mut(&key) {
393 self.reserve_vec(values, 1, operation)?;
394 self.charge_retained(u64_from_index(owned_bytes), operation)?;
395 values.push(value());
396 return Ok(());
397 }
398 self.admit_btree_entry(groups, &key, operation)?;
399 let mut values = self.collection_vec(1, operation)?;
400 self.charge_retained(u64_from_index(owned_bytes), operation)?;
401 values.push(value());
402 groups.insert(key, values);
403 Ok(())
404 })
405 }
406
407 pub fn admit_retained_btree_record<K, V>(
411 &self,
412 owned_bytes: usize,
413 operation: &'static str,
414 ) -> Result<(), CodecError> {
415 let bytes = self
416 .tree_growth_bytes::<K, V>(0, operation)?
417 .checked_add(u64_from_index(owned_bytes))
418 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
419 self.charge_collection_items(1, operation)?;
420 self.charge_retained(bytes, operation)?;
421 self.charge_work(1, operation)
422 }
423
424 pub fn collect_scoped_btree_groups<'ctx, K: Ord, V>(
426 &'ctx self,
427 values: impl IntoIterator<Item = (K, V)>,
428 operation: &'static str,
429 ) -> Result<(BTreeMap<K, Vec<V>>, ScopedReservation<'ctx>), CodecError> {
430 let mut groups = BTreeMap::new();
431 let mut reservation = self.reserve_scoped(0, operation)?;
432 for (key, value) in values {
433 self.push_scoped_btree_group(
434 &mut reservation,
435 &mut groups,
436 key,
437 || value,
438 0,
439 operation,
440 )?;
441 }
442 Ok((groups, reservation))
443 }
444
445 pub fn collect_scoped_btree_map<'ctx, K: Ord, V>(
447 &'ctx self,
448 values: impl IntoIterator<Item = (K, V)>,
449 operation: &'static str,
450 ) -> Result<(BTreeMap<K, V>, ScopedReservation<'ctx>), CodecError> {
451 let mut entries = BTreeMap::new();
452 let mut reservation = self.reserve_scoped(0, operation)?;
453 reservation.with_storage(|| {
454 for (key, value) in values {
455 self.charge_work(u64_from_index(entries.len()) + 1, operation)?;
456 self.insert_btree_map(&mut entries, key, value, operation)?;
457 }
458 Ok::<(), CodecError>(())
459 })?;
460 Ok((entries, reservation))
461 }
462
463 pub fn reserve_scoped_string(
465 &self,
466 reservation: &mut ScopedReservation<'_>,
467 text: &mut String,
468 additional: usize,
469 operation: &'static str,
470 ) -> Result<(), CodecError> {
471 reservation.with_storage(|| self.try_reserve_retained_text(text, additional, operation))
472 }
473
474 pub fn scoped_string(
476 &self,
477 length: usize,
478 operation: &'static str,
479 ) -> Result<(String, ScopedReservation<'_>), CodecError> {
480 let mut reservation = self.reserve_scoped(0, operation)?;
481 let mut text = String::new();
482 self.reserve_scoped_string(&mut reservation, &mut text, length, operation)?;
483 Ok((text, reservation))
484 }
485
486 fn allocation_failed(
487 &self,
488 dimension: ResourceDimension,
489 count: usize,
490 operation: &'static str,
491 ) -> CodecError {
492 match dimension {
493 ResourceDimension::CollectionItems => {
494 self.collection_allocation_failed(count, operation)
495 }
496 ResourceDimension::MaterializedBytes => self
497 .budget
498 .scoped_allocation_failed(u64_from_index(count), operation),
499 _ => self
500 .budget
501 .retained_allocation_failed(u64_from_index(count), operation),
502 }
503 }
504
505 pub fn collection_vec<T>(
507 &self,
508 count: usize,
509 operation: &'static str,
510 ) -> Result<Vec<T>, CodecError> {
511 let mut values = Vec::new();
512 self.reserve_retained_vec_storage(
513 &mut values,
514 count,
515 VecGrowth::Exact,
516 Some(count),
517 operation,
518 )?;
519 Ok(values)
520 }
521
522 pub fn reserve_vec<T>(
524 &self,
525 values: &mut Vec<T>,
526 additional: usize,
527 operation: &'static str,
528 ) -> Result<(), CodecError> {
529 self.reserve_vec_limit(values, additional, operation)
530 .map_err(Into::into)
531 }
532
533 pub fn reserve_vec_limit<T>(
535 &self,
536 values: &mut Vec<T>,
537 additional: usize,
538 operation: &'static str,
539 ) -> Result<(), ResourceLimit> {
540 self.reserve_retained_vec_storage(
541 values,
542 additional,
543 VecGrowth::Amortized,
544 Some(additional),
545 operation,
546 )
547 }
548
549 pub fn collect_indexed_vec<T>(
551 &self,
552 count: usize,
553 operation: &'static str,
554 mut value_at: impl FnMut(usize) -> Result<T, CodecError>,
555 ) -> Result<Vec<T>, CodecError> {
556 let mut values = self.collection_vec(count, operation)?;
557 for index in 0..count {
558 values.push(value_at(index)?);
559 }
560 Ok(values)
561 }
562
563 pub fn push_vec<T>(
565 &self,
566 values: &mut Vec<T>,
567 value: T,
568 operation: &'static str,
569 ) -> Result<(), CodecError> {
570 self.reserve_vec(values, 1, operation)?;
571 values.push(value);
572 Ok(())
573 }
574
575 pub fn push_formatted_retained(
577 &self,
578 values: &mut Vec<String>,
579 args: fmt::Arguments<'_>,
580 slots_operation: &'static str,
581 text_operation: &'static str,
582 ) -> Result<(), CodecError> {
583 self.reserve_vec(values, 1, slots_operation)?;
584 values.push(self.format_retained(args, text_operation)?);
585 Ok(())
586 }
587
588 pub fn append_vec<T>(
590 &self,
591 target: &mut Vec<T>,
592 source: &mut Vec<T>,
593 operation: &'static str,
594 ) -> Result<(), CodecError> {
595 self.reserve_vec(target, source.len(), operation)?;
596 target.append(source);
597 Ok(())
598 }
599
600 pub fn extend_vec<T>(
602 &self,
603 target: &mut Vec<T>,
604 mut source: Vec<T>,
605 operation: &'static str,
606 ) -> Result<(), CodecError> {
607 self.append_vec(target, &mut source, operation)
608 }
609
610 pub fn collect_vec<T>(
612 &self,
613 values: impl IntoIterator<Item = T>,
614 operation: &'static str,
615 ) -> Result<Vec<T>, CodecError> {
616 let mut out = Vec::new();
617 for value in values {
618 self.push_vec(&mut out, value, operation)?;
619 }
620 Ok(out)
621 }
622
623 pub fn try_collect_vec<T, E: From<CodecError>>(
625 &self,
626 values: impl IntoIterator<Item = Result<T, E>>,
627 operation: &'static str,
628 ) -> Result<Vec<T>, E> {
629 let mut out = Vec::new();
630 for value in values {
631 self.push_vec(&mut out, value?, operation)
632 .map_err(E::from)?;
633 }
634 Ok(out)
635 }
636
637 pub fn insert_scoped_btree_value<T: Ord>(
639 &self,
640 reservation: &mut ScopedReservation<'_>,
641 values: &mut BTreeSet<T>,
642 value: T,
643 operation: &'static str,
644 ) -> Result<bool, CodecError> {
645 reservation.with_storage(|| self.insert_btree_set(values, value, operation))
646 }
647
648 pub fn insert_hash_set<T: Eq + Hash>(
650 &self,
651 values: &mut HashSet<T>,
652 value: T,
653 operation: &'static str,
654 ) -> Result<bool, CodecError> {
655 if values.contains(&value) {
656 return Ok(false);
657 }
658 self.reserve_set(values, 1, operation)?;
659 Ok(values.insert(value))
660 }
661
662 pub fn insert_string_set(
664 &self,
665 values: &mut HashSet<String>,
666 value: &str,
667 operation: &'static str,
668 ) -> Result<bool, CodecError> {
669 if values.contains(value) {
670 return Ok(false);
671 }
672 self.reserve_set(values, 1, operation)?;
673 let owned = self.copy_retained_text(value, operation)?;
674 Ok(values.insert(owned))
675 }
676
677 pub fn extend_hash_set<T: Eq + Hash>(
679 &self,
680 values: &mut HashSet<T>,
681 additions: impl IntoIterator<Item = T>,
682 operation: &'static str,
683 ) -> Result<(), CodecError> {
684 for value in additions {
685 self.insert_hash_set(values, value, operation)?;
686 }
687 Ok(())
688 }
689
690 pub fn collect_hash_set<T: Eq + Hash>(
692 &self,
693 values: impl IntoIterator<Item = T>,
694 operation: &'static str,
695 ) -> Result<HashSet<T>, CodecError> {
696 let mut out = HashSet::new();
697 for value in values {
698 self.insert_hash_set(&mut out, value, operation)?;
699 }
700 Ok(out)
701 }
702
703 pub fn admit_hash_map_entry<K: Eq + Hash, V>(
705 &self,
706 values: &mut HashMap<K, V>,
707 key: &K,
708 operation: &'static str,
709 ) -> Result<(), CodecError> {
710 if !values.contains_key(key) {
711 self.reserve_map(values, 1, operation)?;
712 }
713 Ok(())
714 }
715
716 pub fn push_hash_group<K: Eq + Hash, V>(
718 &self,
719 values: &mut HashMap<K, Vec<V>>,
720 key: K,
721 value: V,
722 index_operation: &'static str,
723 value_operation: &'static str,
724 ) -> Result<(), CodecError> {
725 if let Some(group) = values.get_mut(&key) {
726 return self.push_vec(group, value, value_operation);
727 }
728 self.charge_collection_items(1, index_operation)?;
729 self.charge_collection_items(1, value_operation)?;
730 let mut group = self.vector_storage(1, value_operation)?;
731 let bytes = self.charge_hash_growth::<(K, Vec<V>)>(
732 values.len(),
733 values.capacity(),
734 1,
735 index_operation,
736 )?;
737 values.try_reserve(1).map_err(|_| {
738 self.budget
739 .retained_allocation_failed(u64_from_index(bytes), index_operation)
740 })?;
741 group.push(value);
742 values.insert(key, group);
743 Ok(())
744 }
745
746 pub fn insert_hash_map<K: Eq + Hash, V>(
748 &self,
749 values: &mut HashMap<K, V>,
750 key: K,
751 value: V,
752 operation: &'static str,
753 ) -> Result<Option<V>, CodecError> {
754 self.admit_hash_map_entry(values, &key, operation)?;
755 Ok(values.insert(key, value))
756 }
757
758 pub fn collect_hash_map<K: Eq + Hash, V>(
760 &self,
761 values: impl IntoIterator<Item = (K, V)>,
762 operation: &'static str,
763 ) -> Result<HashMap<K, V>, CodecError> {
764 let mut out = HashMap::new();
765 for (key, value) in values {
766 self.insert_hash_map(&mut out, key, value, operation)?;
767 }
768 Ok(out)
769 }
770
771 pub fn copy_scoped_text(
773 &self,
774 text: &str,
775 reservation: &mut ScopedReservation<'_>,
776 operation: &'static str,
777 ) -> Result<String, CodecError> {
778 reservation.with_storage(|| self.copy_retained_text(text, operation))
779 }
780
781 fn linear_growth<T>(
782 &self,
783 len: usize,
784 capacity: usize,
785 count: usize,
786 operation: &'static str,
787 ) -> Result<(usize, usize), CodecError> {
788 let required = len
789 .checked_add(count)
790 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
791 if std::mem::size_of::<T>() == 0 || required <= capacity {
792 return Ok((0, 0));
793 }
794 let minimum = match std::mem::size_of::<T>() {
795 1 => 8,
796 2..=1024 => 4,
797 _ => 1,
798 };
799 let target = capacity
800 .checked_mul(2)
801 .ok_or_else(|| self.retained_size_overflow_limit(operation))?
802 .max(required)
803 .max(minimum);
804 let bytes = (target - capacity)
805 .checked_mul(std::mem::size_of::<T>())
806 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
807 self.charge_retained(u64_from_index(bytes), operation)?;
808 Ok((target - len, bytes))
809 }
810
811 pub fn push_back<T>(
813 &self,
814 values: &mut VecDeque<T>,
815 value: T,
816 operation: &'static str,
817 ) -> Result<(), CodecError> {
818 let (additional, bytes) =
819 self.linear_growth::<T>(values.len(), values.capacity(), 1, operation)?;
820 self.charge_collection_items(1, operation)?;
821 values.try_reserve_exact(additional).map_err(|_| {
822 self.budget
823 .retained_allocation_failed(u64_from_index(bytes), operation)
824 })?;
825 values.push_back(value);
826 Ok(())
827 }
828
829 pub fn push_front<T>(
831 &self,
832 values: &mut VecDeque<T>,
833 value: T,
834 operation: &'static str,
835 ) -> Result<(), CodecError> {
836 let (additional, bytes) =
837 self.linear_growth::<T>(values.len(), values.capacity(), 1, operation)?;
838 self.charge_collection_items(1, operation)?;
839 values.try_reserve_exact(additional).map_err(|_| {
840 self.budget
841 .retained_allocation_failed(u64_from_index(bytes), operation)
842 })?;
843 values.push_front(value);
844 Ok(())
845 }
846
847 pub fn reserve_heap<T: Ord>(
849 &self,
850 values: &mut BinaryHeap<T>,
851 count: usize,
852 operation: &'static str,
853 ) -> Result<(), CodecError> {
854 let (additional, bytes) =
855 self.linear_growth::<T>(values.len(), values.capacity(), count, operation)?;
856 self.charge_collection_items(u64_from_index(count), operation)?;
857 values.try_reserve_exact(additional).map_err(|_| {
858 self.budget
859 .retained_allocation_failed(u64_from_index(bytes), operation)
860 })
861 }
862
863 pub fn optional_collection_vec<T>(
865 &self,
866 present: bool,
867 count: usize,
868 operation: &'static str,
869 ) -> Result<Option<Vec<T>>, CodecError> {
870 if present {
871 Ok(Some(self.collection_vec(count, operation)?))
872 } else {
873 Ok(None)
874 }
875 }
876
877 pub fn copy_rows<T: Copy>(
879 &self,
880 values: &[T],
881 row_len: usize,
882 row_operation: &'static str,
883 item_operation: &'static str,
884 ) -> Result<Vec<Vec<T>>, CodecError> {
885 if row_len == 0 {
886 return Err(CodecError::malformed("row width must be nonzero"));
887 }
888 self.try_collect_retained_with(values.chunks(row_len), row_operation, |row| {
889 self.copy_slice(row, item_operation)
890 })
891 }
892
893 pub fn try_collect_retained_with<I, T, E: From<CodecError>>(
895 &self,
896 values: impl IntoIterator<Item = I>,
897 operation: &'static str,
898 mut map: impl FnMut(I) -> Result<T, E>,
899 ) -> Result<Vec<T>, E> {
900 let values = values.into_iter();
901 let (minimum, maximum) = values.size_hint();
902 let mut collected = Vec::new();
903 for (index, value) in values.enumerate() {
904 self.charge_work(1, operation)?;
905 if index == 0 && maximum == Some(minimum) {
906 self.reserve_retained_vec_storage(
907 &mut collected,
908 minimum.max(1),
909 VecGrowth::Exact,
910 Some(1),
911 operation,
912 )
913 .map_err(CodecError::from)?;
914 } else {
915 self.reserve_retained_vec_storage(
916 &mut collected,
917 1,
918 VecGrowth::Amortized,
919 Some(1),
920 operation,
921 )
922 .map_err(CodecError::from)?;
923 }
924 collected.push(map(value)?);
925 }
926 Ok(collected)
927 }
928
929 pub fn copy_slice<T: Copy>(
931 &self,
932 values: &[T],
933 operation: &'static str,
934 ) -> Result<Vec<T>, CodecError> {
935 self.charge_work(u64_from_index(values.len()), operation)?;
936 let mut copy = self.collection_vec(values.len(), operation)?;
937 copy.extend_from_slice(values);
938 Ok(copy)
939 }
940
941 pub fn collect_options<T>(
943 &self,
944 values: impl IntoIterator<Item = Option<T>>,
945 operation: &'static str,
946 ) -> Result<Option<Vec<T>>, CodecError> {
947 let mut collected = Vec::new();
948 for value in values {
949 let Some(value) = value else { return Ok(None) };
950 self.push_vec(&mut collected, value, operation)?;
951 }
952 Ok(Some(collected))
953 }
954
955 pub fn collect_fallible_options<T, E: Into<CodecError>>(
957 &self,
958 values: impl IntoIterator<Item = Result<Option<T>, E>>,
959 operation: &'static str,
960 ) -> Result<Option<Vec<T>>, CodecError> {
961 let mut collected = Vec::new();
962 for value in values {
963 let Some(value) = value.map_err(Into::into)? else {
964 return Ok(None);
965 };
966 self.push_vec(&mut collected, value, operation)?;
967 }
968 Ok(Some(collected))
969 }
970
971 pub fn collect_string_set<'a>(
973 &self,
974 values: impl IntoIterator<Item = &'a str>,
975 operation: &'static str,
976 ) -> Result<HashSet<String>, CodecError> {
977 let mut collected = HashSet::new();
978 for value in values {
979 self.insert_string_set(&mut collected, value, operation)?;
980 }
981 Ok(collected)
982 }
983
984 pub fn copy_retained_rows<T: Copy>(
986 &self,
987 rows: &[Vec<T>],
988 row_operation: &'static str,
989 item_operation: &'static str,
990 ) -> Result<Vec<Vec<T>>, CodecError> {
991 self.try_collect_retained_with(rows, row_operation, |row| {
992 self.copy_slice(row, item_operation)
993 })
994 }
995
996 pub fn copy_retained_set<T: Copy + Eq + Hash>(
998 &self,
999 values: &HashSet<T>,
1000 operation: &'static str,
1001 ) -> Result<HashSet<T>, CodecError> {
1002 self.charge_work(u64_from_index(values.len()), operation)?;
1003 let mut copy = HashSet::new();
1004 self.reserve_set(&mut copy, values.len(), operation)?;
1005 copy.extend(values.iter().copied());
1006 Ok(copy)
1007 }
1008
1009 fn hash_storage_bytes<T>(
1013 &self,
1014 capacity: usize,
1015 operation: &'static str,
1016 ) -> Result<usize, ResourceLimit> {
1017 if capacity == 0 {
1018 return Ok(0);
1019 }
1020 let buckets = if capacity < 4 {
1021 Some(4)
1022 } else if capacity < 8 {
1023 Some(8)
1024 } else {
1025 capacity
1026 .checked_mul(8)
1027 .and_then(|slots| (slots / 7).checked_next_power_of_two())
1028 }
1029 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
1030 let alignment = std::mem::align_of::<T>().max(16);
1031 buckets
1032 .checked_mul(std::mem::size_of::<T>())
1033 .and_then(|bytes| bytes.checked_add(alignment - 1))
1034 .and_then(|bytes| bytes.checked_add(buckets))
1035 .and_then(|bytes| bytes.checked_add(16))
1036 .ok_or_else(|| self.retained_size_overflow_limit(operation))
1037 }
1038
1039 fn charge_hash_growth<T>(
1040 &self,
1041 len: usize,
1042 capacity: usize,
1043 count: usize,
1044 operation: &'static str,
1045 ) -> Result<usize, ResourceLimit> {
1046 let required = len
1047 .checked_add(count)
1048 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
1049 if required <= capacity {
1050 return Ok(0);
1051 }
1052 let minimum = match std::mem::size_of::<T>() {
1053 0..=1 => 14,
1054 2..=3 => 7,
1055 _ => 3,
1056 };
1057 let bytes = self.hash_storage_bytes::<T>(required.max(minimum), operation)?
1058 - self.hash_storage_bytes::<T>(capacity, operation)?;
1059 self.charge_retained_limit(u64_from_index(bytes), operation)?;
1060 Ok(bytes)
1061 }
1062
1063 pub fn reserve_set<T: Eq + Hash>(
1065 &self,
1066 values: &mut HashSet<T>,
1067 count: usize,
1068 operation: &'static str,
1069 ) -> Result<(), CodecError> {
1070 let bytes =
1071 self.charge_hash_growth::<T>(values.len(), values.capacity(), count, operation)?;
1072 self.charge_collection_items(u64_from_index(count), operation)?;
1073 values.try_reserve(count).map_err(|_| {
1074 self.budget
1075 .retained_allocation_failed(u64_from_index(bytes), operation)
1076 })
1077 }
1078
1079 pub fn reserve_map<K: Eq + Hash, V>(
1081 &self,
1082 values: &mut HashMap<K, V>,
1083 count: usize,
1084 operation: &'static str,
1085 ) -> Result<(), CodecError> {
1086 let bytes =
1087 self.charge_hash_growth::<(K, V)>(values.len(), values.capacity(), count, operation)?;
1088 self.charge_collection_items(u64_from_index(count), operation)?;
1089 values.try_reserve(count).map_err(|_| {
1090 self.budget
1091 .retained_allocation_failed(u64_from_index(bytes), operation)
1092 })
1093 }
1094
1095 fn tree_growth_bytes<K, V>(
1103 &self,
1104 len: usize,
1105 operation: &'static str,
1106 ) -> Result<u64, ResourceLimit> {
1107 let alignment = std::mem::align_of::<K>()
1108 .max(std::mem::align_of::<V>())
1109 .max(std::mem::align_of::<usize>());
1110 let next = len
1111 .checked_add(1)
1112 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
1113 let before = if len == 0 { 0 } else { (len - 1) / 5 + 1 };
1114 let nodes = (next - 1) / 5 + 1 - before;
1115 std::mem::size_of::<K>()
1116 .checked_add(std::mem::size_of::<V>())
1117 .and_then(|bytes| bytes.checked_mul(11))
1118 .and_then(|bytes| bytes.checked_add(16 * std::mem::size_of::<usize>()))
1119 .and_then(|bytes| bytes.checked_add(2 * alignment))
1120 .and_then(|bytes| bytes.checked_mul(nodes))
1121 .map(u64_from_index)
1122 .ok_or_else(|| self.retained_size_overflow_limit(operation))
1123 }
1124
1125 pub fn admit_btree_node_storage<K, V>(
1127 &self,
1128 len: usize,
1129 operation: &'static str,
1130 ) -> Result<(), CodecError> {
1131 self.charge_retained(self.tree_growth_bytes::<K, V>(len, operation)?, operation)
1132 }
1133
1134 pub fn admit_btree_entry<K: Ord, V>(
1136 &self,
1137 values: &BTreeMap<K, V>,
1138 key: &K,
1139 operation: &'static str,
1140 ) -> Result<(), CodecError> {
1141 if !values.contains_key(key) {
1142 self.admit_btree_node_storage::<K, V>(values.len(), operation)?;
1143 self.charge_collection_items(1, operation)?;
1144 }
1145 Ok(())
1146 }
1147
1148 pub fn insert_btree_map<K: Ord, V>(
1150 &self,
1151 values: &mut BTreeMap<K, V>,
1152 key: K,
1153 value: V,
1154 operation: &'static str,
1155 ) -> Result<Option<V>, CodecError> {
1156 self.admit_btree_entry(values, &key, operation)?;
1157 Ok(values.insert(key, value))
1158 }
1159
1160 pub fn insert_btree_set<T: Ord>(
1162 &self,
1163 values: &mut BTreeSet<T>,
1164 value: T,
1165 operation: &'static str,
1166 ) -> Result<bool, CodecError> {
1167 if values.contains(&value) {
1168 return Ok(false);
1169 }
1170 self.charge_retained(
1171 self.tree_growth_bytes::<T, ()>(values.len(), operation)?,
1172 operation,
1173 )?;
1174 self.charge_collection_items(1, operation)?;
1175 Ok(values.insert(value))
1176 }
1177
1178 pub fn collect_btree_set<T: Ord>(
1180 &self,
1181 values: impl IntoIterator<Item = T>,
1182 operation: &'static str,
1183 ) -> Result<BTreeSet<T>, CodecError> {
1184 let mut out = BTreeSet::new();
1185 for value in values {
1186 self.insert_btree_set(&mut out, value, operation)?;
1187 }
1188 Ok(out)
1189 }
1190
1191 pub fn push_btree_group<K: Ord, V>(
1193 &self,
1194 groups: &mut BTreeMap<K, Vec<V>>,
1195 key: K,
1196 value: V,
1197 group_operation: &'static str,
1198 item_operation: &'static str,
1199 ) -> Result<(), CodecError> {
1200 if let Some(values) = groups.get_mut(&key) {
1201 return self.push_vec(values, value, item_operation);
1202 }
1203 self.admit_btree_entry(groups, &key, group_operation)?;
1204 let mut values = self.collection_vec(1, item_operation)?;
1205 values.push(value);
1206 groups.insert(key, values);
1207 Ok(())
1208 }
1209
1210 pub fn insert_btree_group_set<K: Ord, V: Ord>(
1212 &self,
1213 groups: &mut BTreeMap<K, BTreeSet<V>>,
1214 key: K,
1215 value: V,
1216 group_operation: &'static str,
1217 item_operation: &'static str,
1218 ) -> Result<(), CodecError> {
1219 if let Some(values) = groups.get_mut(&key) {
1220 self.insert_btree_set(values, value, item_operation)?;
1221 return Ok(());
1222 }
1223 self.admit_btree_entry(groups, &key, group_operation)?;
1224 let mut values = BTreeSet::new();
1225 self.insert_btree_set(&mut values, value, item_operation)?;
1226 groups.insert(key, values);
1227 Ok(())
1228 }
1229
1230 pub fn resize_retained_bytes(
1232 &self,
1233 values: &mut Vec<u8>,
1234 length: usize,
1235 fill: u8,
1236 operation: &'static str,
1237 ) -> Result<(), CodecError> {
1238 if let Some(additional) = length.checked_sub(values.len()) {
1239 self.reserve_capacity(values, additional, operation)?;
1240 for _ in 0..additional {
1241 values.push(fill);
1242 }
1243 } else {
1244 values.truncate(length);
1245 }
1246 Ok(())
1247 }
1248
1249 pub fn extend_retained_bytes(
1251 &self,
1252 target: &mut Vec<u8>,
1253 source: &[u8],
1254 operation: &'static str,
1255 ) -> Result<(), CodecError> {
1256 self.reserve_vec(target, source.len(), operation)?;
1257 target.extend_from_slice(source);
1258 Ok(())
1259 }
1260
1261 pub fn temporary_vec<T>(
1263 &self,
1264 count: usize,
1265 operation: &'static str,
1266 ) -> Result<(Vec<T>, ScopedReservation<'_>), CodecError> {
1267 let mut reservation = self.reserve_scoped(0, operation)?;
1268 let values = reservation.with_storage(|| self.collection_vec(count, operation))?;
1269 Ok((values, reservation))
1270 }
1271
1272 pub fn temporary_set<T: Eq + Hash>(
1274 &self,
1275 count: usize,
1276 operation: &'static str,
1277 ) -> Result<(HashSet<T>, ScopedReservation<'_>), CodecError> {
1278 self.temporary_set_limit(count, operation)
1279 .map_err(Into::into)
1280 }
1281
1282 pub fn temporary_set_limit<T: Eq + Hash>(
1284 &self,
1285 count: usize,
1286 operation: &'static str,
1287 ) -> Result<(HashSet<T>, ScopedReservation<'_>), ResourceLimit> {
1288 let mut reservation = self.reserve_scoped_limit(0, operation)?;
1289 let mut values = HashSet::new();
1290 reservation.with_storage_limit(|| {
1291 let bytes = self.charge_hash_growth::<T>(0, 0, count, operation)?;
1292 self.charge_collection_items_limit(u64_from_index(count), operation)?;
1293 values.try_reserve(count).map_err(|_| {
1294 self.budget
1295 .retained_allocation_failed_limit(u64_from_index(bytes), operation)
1296 })
1297 })?;
1298 Ok((values, reservation))
1299 }
1300
1301 pub fn collect_scoped_string_set<'text>(
1303 &self,
1304 count: usize,
1305 values: impl IntoIterator<Item = &'text str>,
1306 operation: &'static str,
1307 ) -> Result<(HashSet<&'text str>, ScopedReservation<'_>), CodecError> {
1308 let (mut output, mut reservation) = self.temporary_set(count, operation)?;
1309 let mut remaining = count;
1310 reservation.with_storage(|| {
1311 for value in values {
1312 self.charge_work(
1313 u64_from_index(value.len())
1314 .checked_mul(2)
1315 .and_then(|work| work.checked_add(1))
1316 .ok_or_else(|| self.refuse_codec_limit(operation, u64::MAX, u64::MAX))?,
1317 operation,
1318 )?;
1319 if !output.contains(value) {
1320 if remaining == 0 {
1321 self.reserve_set(&mut output, 1, operation)?;
1322 } else {
1323 remaining -= 1;
1324 }
1325 output.insert(value);
1326 }
1327 }
1328 Ok::<(), CodecError>(())
1329 })?;
1330 Ok((output, reservation))
1331 }
1332
1333 pub fn collect_scoped_string_map<'text, V>(
1335 &self,
1336 count: usize,
1337 values: impl IntoIterator<Item = (&'text str, V)>,
1338 operation: &'static str,
1339 ) -> Result<(HashMap<&'text str, V>, ScopedReservation<'_>), CodecError> {
1340 let mut reservation = self.reserve_scoped(0, operation)?;
1341 let mut output = HashMap::new();
1342 reservation.with_storage(|| {
1343 self.reserve_map(&mut output, count, operation)?;
1344 let mut remaining = count;
1345 for (key, value) in values {
1346 self.charge_work(
1347 u64_from_index(key.len())
1348 .checked_mul(2)
1349 .and_then(|work| work.checked_add(1))
1350 .ok_or_else(|| self.refuse_codec_limit(operation, u64::MAX, u64::MAX))?,
1351 operation,
1352 )?;
1353 if !output.contains_key(key) {
1354 if remaining == 0 {
1355 self.reserve_map(&mut output, 1, operation)?;
1356 } else {
1357 remaining -= 1;
1358 }
1359 }
1360 output.insert(key, value);
1361 }
1362 Ok::<(), CodecError>(())
1363 })?;
1364 Ok((output, reservation))
1365 }
1366
1367 pub fn temporary_queue<T>(
1369 &self,
1370 count: usize,
1371 operation: &'static str,
1372 ) -> Result<(VecDeque<T>, ScopedReservation<'_>), CodecError> {
1373 let mut reservation = self.reserve_scoped(0, operation)?;
1374 let mut values = VecDeque::new();
1375 reservation.with_storage(|| {
1376 let bytes = count
1377 .checked_mul(std::mem::size_of::<T>())
1378 .ok_or_else(|| self.retained_size_overflow_limit(operation))?;
1379 self.charge_retained(u64_from_index(bytes), operation)?;
1380 self.charge_collection_items(u64_from_index(count), operation)?;
1381 values.try_reserve_exact(count).map_err(|_| {
1382 self.budget
1383 .retained_allocation_failed(u64_from_index(bytes), operation)
1384 })
1385 })?;
1386 Ok((values, reservation))
1387 }
1388
1389 pub fn charge_formatted_retained(
1391 &self,
1392 args: fmt::Arguments<'_>,
1393 operation: &'static str,
1394 ) -> Result<(), CodecError> {
1395 let length = self.formatted_length(args, operation)?;
1396 self.charge_retained(u64_from_index(length), operation)
1397 }
1398
1399 pub fn format_retained(
1401 &self,
1402 args: fmt::Arguments<'_>,
1403 operation: &'static str,
1404 ) -> Result<String, CodecError> {
1405 let mut text = String::new();
1406 self.append_formatted_retained(&mut text, args, operation)?;
1407 Ok(text)
1408 }
1409
1410 pub fn format_scoped(
1412 &self,
1413 args: fmt::Arguments<'_>,
1414 operation: &'static str,
1415 ) -> Result<(String, ScopedReservation<'_>), CodecError> {
1416 let mut reservation = self.reserve_scoped(0, operation)?;
1417 let text = self.format_scoped_text(&mut reservation, args, operation)?;
1418 Ok((text, reservation))
1419 }
1420
1421 pub fn append_retained(
1423 &self,
1424 output: &mut String,
1425 suffix: &str,
1426 operation: &'static str,
1427 ) -> Result<(), CodecError> {
1428 self.charge_work(u64_from_index(suffix.len()), operation)?;
1429 self.try_reserve_retained_text(output, suffix.len(), operation)?;
1430 output.push_str(suffix);
1431 Ok(())
1432 }
1433
1434 pub fn append_formatted_retained(
1436 &self,
1437 output: &mut String,
1438 args: fmt::Arguments<'_>,
1439 operation: &'static str,
1440 ) -> Result<(), CodecError> {
1441 struct Output<'ctx, 'arena, 'text> {
1442 ctx: &'ctx DecodeContext<'arena>,
1443 text: &'text mut String,
1444 operation: &'static str,
1445 refusal: Option<CodecError>,
1446 }
1447 impl Write for Output<'_, '_, '_> {
1448 fn write_str(&mut self, fragment: &str) -> fmt::Result {
1449 if let Err(error) = self
1450 .ctx
1451 .append_retained(self.text, fragment, self.operation)
1452 {
1453 self.refusal = Some(error);
1454 return Err(fmt::Error);
1455 }
1456 Ok(())
1457 }
1458 }
1459 let length = self.formatted_length(args, operation)?;
1460 self.try_reserve_retained_text(output, length, operation)?;
1461 let mut writer = Output {
1462 ctx: self,
1463 text: output,
1464 operation,
1465 refusal: None,
1466 };
1467 match fmt::write(&mut writer, args) {
1468 Ok(()) => Ok(()),
1469 Err(error) => Err(match writer.refusal {
1470 Some(refusal) => refusal,
1471 None => CodecError::malformed(error),
1472 }),
1473 }
1474 }
1475
1476 pub fn retained_string(
1478 &self,
1479 length: usize,
1480 operation: &'static str,
1481 ) -> Result<String, CodecError> {
1482 self.charge_retained(u64_from_index(length), operation)?;
1483 let mut value = String::new();
1484 value.try_reserve_exact(length).map_err(|_| {
1485 self.allocation_failed(ResourceDimension::RetainedBytes, length, operation)
1486 })?;
1487 Ok(value)
1488 }
1489
1490 pub fn retained_suffix(
1492 &self,
1493 value: &str,
1494 suffix: &str,
1495 operation: &'static str,
1496 ) -> Result<String, CodecError> {
1497 let mut output = self.copy_retained_text(value, operation)?;
1498 self.append_retained(&mut output, suffix, operation)?;
1499 Ok(output)
1500 }
1501
1502 pub fn copy_retained_strings(
1504 &self,
1505 values: &[String],
1506 operation: &'static str,
1507 ) -> Result<Vec<String>, CodecError> {
1508 let mut copies = self.collection_vec(values.len(), operation)?;
1509 for value in values {
1510 copies.push(self.copy_retained_text(value, operation)?);
1511 }
1512 Ok(copies)
1513 }
1514
1515 pub fn join_retained<S: AsRef<str>>(
1517 &self,
1518 parts: &[S],
1519 separator: &str,
1520 operation: &'static str,
1521 ) -> Result<String, CodecError> {
1522 let mut count = 0_usize;
1523 for part in parts {
1524 count = count
1525 .checked_add(part.as_ref().len())
1526 .ok_or_else(|| self.refuse_codec_limit(operation, u64::MAX, u64::MAX))?;
1527 }
1528 let gaps = if parts.is_empty() { 0 } else { parts.len() - 1 };
1529 count = separator
1530 .len()
1531 .checked_mul(gaps)
1532 .and_then(|separators| count.checked_add(separators))
1533 .ok_or_else(|| self.refuse_codec_limit(operation, u64::MAX, u64::MAX))?;
1534 self.charge_retained(u64_from_index(count), operation)?;
1535 let mut output = String::new();
1536 output.try_reserve_exact(count).map_err(|_| {
1537 self.allocation_failed(ResourceDimension::RetainedBytes, count, operation)
1538 })?;
1539 for (index, part) in parts.iter().enumerate() {
1540 if index != 0 {
1541 output.push_str(separator);
1542 }
1543 output.push_str(part.as_ref());
1544 }
1545 Ok(output)
1546 }
1547
1548 pub fn join_display_retained<T: fmt::Display>(
1550 &self,
1551 values: impl IntoIterator<Item = T>,
1552 separator: &str,
1553 operation: &'static str,
1554 ) -> Result<String, CodecError> {
1555 struct ChargedText<'a, 'arena> {
1556 ctx: &'a DecodeContext<'arena>,
1557 operation: &'static str,
1558 text: String,
1559 refusal: Option<CodecError>,
1560 }
1561 impl Write for ChargedText<'_, '_> {
1562 fn write_str(&mut self, fragment: &str) -> fmt::Result {
1563 if let Err(error) =
1564 self.ctx
1565 .append_retained(&mut self.text, fragment, self.operation)
1566 {
1567 self.refusal = Some(error);
1568 return Err(fmt::Error);
1569 }
1570 Ok(())
1571 }
1572 }
1573 let mut output = ChargedText {
1574 ctx: self,
1575 operation,
1576 text: String::new(),
1577 refusal: None,
1578 };
1579 for (index, value) in values.into_iter().enumerate() {
1580 let written = if index == 0 {
1581 output.write_fmt(format_args!("{value}"))
1582 } else {
1583 output
1584 .write_str(separator)
1585 .and_then(|()| output.write_fmt(format_args!("{value}")))
1586 };
1587 if written.is_err() {
1588 return Err(match output.refusal {
1589 Some(error) => error,
1590 None => self.refuse_codec_limit(operation, 0, 1),
1591 });
1592 }
1593 }
1594 Ok(output.text)
1595 }
1596
1597 fn formatted_length(
1598 &self,
1599 args: fmt::Arguments<'_>,
1600 operation: &'static str,
1601 ) -> Result<usize, CodecError> {
1602 struct Count<'ctx, 'arena> {
1603 ctx: &'ctx DecodeContext<'arena>,
1604 operation: &'static str,
1605 length: Option<usize>,
1606 refusal: Option<CodecError>,
1607 }
1608 impl Write for Count<'_, '_> {
1609 fn write_str(&mut self, value: &str) -> fmt::Result {
1610 if let Err(error) = self
1611 .ctx
1612 .charge_work(u64_from_index(value.len()), self.operation)
1613 {
1614 self.refusal = Some(error);
1615 return Err(fmt::Error);
1616 }
1617 self.length = self.length.and_then(|total| total.checked_add(value.len()));
1618 self.length.map(|_| ()).ok_or(fmt::Error)
1619 }
1620 }
1621 let mut count = Count {
1622 ctx: self,
1623 operation,
1624 length: Some(0),
1625 refusal: None,
1626 };
1627 if fmt::write(&mut count, args).is_err() {
1628 return Err(match count.refusal {
1629 Some(error) => error,
1630 None => self.refuse_codec_limit(operation, u64::MAX, u64::MAX),
1631 });
1632 }
1633 count
1634 .length
1635 .ok_or_else(|| self.refuse_codec_limit(operation, u64::MAX, u64::MAX))
1636 }
1637}
1638
1639#[cfg(test)]
1640mod tests;
1641
1642#[cfg(test)]
1643mod temporary_capacity_tests {
1644 #[test]
1645 fn temporary_reserve_charges_no_storage_with_available_capacity() {
1646 use super::DecodeContext;
1647 let arena = super::super::DecodeArena::new();
1648 let mut policy = super::super::DecodePolicy::service();
1649 policy.limits.max_materialized_bytes = 0;
1650 let (ctx, _) =
1651 DecodeContext::from_root_bytes(&[], &arena, &policy).expect("admitted test operation");
1652 let mut values = Vec::<u64>::with_capacity(8);
1653 let capacity = values.capacity();
1654 let storage = ctx
1655 .reserve_temporary_vec(&mut values, 3, "existing temporary capacity")
1656 .expect("admitted test operation");
1657 assert_eq!(values.capacity(), capacity);
1658 drop(storage);
1659 }
1660}
1661
1662#[cfg(test)]
1663mod tree_work_tests {
1664 use std::cell::Cell;
1665 use std::cmp::Ordering;
1666 use std::collections::BTreeSet;
1667
1668 use super::DecodeContext;
1669 use crate::decode::{DecodeArena, DecodePolicy};
1670
1671 thread_local! {
1672 static COMPARISONS: Cell<u64> = const { Cell::new(0) };
1673 }
1674
1675 #[derive(Debug)]
1676 struct CountedKey {
1677 value: usize,
1678 }
1679
1680 impl PartialEq for CountedKey {
1681 fn eq(&self, other: &Self) -> bool {
1682 self.value == other.value
1683 }
1684 }
1685
1686 impl Eq for CountedKey {}
1687
1688 impl PartialOrd for CountedKey {
1689 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1690 Some(self.cmp(other))
1691 }
1692 }
1693
1694 impl Ord for CountedKey {
1695 fn cmp(&self, other: &Self) -> Ordering {
1696 COMPARISONS.with(|count| count.set(count.get() + 1));
1697 self.value.cmp(&other.value)
1698 }
1699 }
1700
1701 #[test]
1702 fn scoped_tree_work_refuses_before_comparing_or_inserting() {
1703 let arena = DecodeArena::new();
1704 let mut policy = DecodePolicy::service();
1705 policy.limits.max_work_units = 0;
1706 let ctx = DecodeContext::new(&arena, &policy, false);
1707 COMPARISONS.with(|count| count.set(0));
1708 let mut values = BTreeSet::from([CountedKey { value: 0 }]);
1709 let mut storage = ctx.reserve_scoped(0, "tree test storage").expect("scope");
1710 let error = ctx
1711 .insert_scoped_btree_set(
1712 &mut storage,
1713 &mut values,
1714 CountedKey { value: 1 },
1715 "tree test comparisons",
1716 "tree test storage",
1717 )
1718 .expect_err("lookup exceeds work allowance");
1719 assert!(matches!(error, crate::CodecError::ResourceLimit(limit)
1720 if limit.operation == "tree test comparisons"));
1721 assert_eq!(COMPARISONS.with(Cell::get), 0);
1722 assert_eq!(values.len(), 1);
1723 }
1724
1725 #[test]
1726 fn scoped_tree_work_bounds_comparisons_without_billing_full_scans() {
1727 const COUNT: usize = 16_384;
1728 for order in 0..3 {
1729 let arena = DecodeArena::new();
1730 let mut policy = DecodePolicy::service();
1731 policy.limits.max_work_units = 3_000_000;
1733 let ctx = DecodeContext::new(&arena, &policy, false);
1734 COMPARISONS.with(|count| count.set(0));
1735 let mut values = BTreeSet::new();
1736 let mut storage = ctx.reserve_scoped(0, "tree test storage").expect("scope");
1737 for index in 0..COUNT {
1738 let value = match order {
1739 0 => index,
1740 1 => COUNT - index - 1,
1741 _ => (index * 8191) % COUNT,
1742 };
1743 assert!(ctx
1744 .insert_scoped_btree_set(
1745 &mut storage,
1746 &mut values,
1747 CountedKey { value },
1748 "tree test comparisons",
1749 "tree test storage",
1750 )
1751 .expect("indexed insertion fits work allowance"));
1752 }
1753 for value in 0..=COUNT {
1754 ctx.charge_btree_lookup(values.len(), "tree test membership")
1755 .expect("indexed membership fits work allowance");
1756 assert_eq!(values.contains(&CountedKey { value }), value < COUNT);
1757 }
1758 assert!(!ctx
1759 .insert_scoped_btree_set(
1760 &mut storage,
1761 &mut values,
1762 CountedKey { value: COUNT / 2 },
1763 "tree test comparisons",
1764 "tree test storage",
1765 )
1766 .expect("duplicate fits work allowance"));
1767 assert_eq!(values.len(), COUNT);
1768 let refusal = ctx
1769 .charge_work_limit(u64::MAX, "read tree test work")
1770 .expect_err("measurement exceeds the work limit");
1771 assert!(refusal.used >= COMPARISONS.with(Cell::get));
1772 assert!(refusal.used < policy.limits.max_work_units);
1773 }
1774 }
1775}