(
schema: &Schema,
names: &HashMap<Name, S>,
enclosing_namespace: NamespaceRef,
reader: &mut R,
)
| 75 | /// shared budget of [`max_allocation_bytes`] bytes, instead of each |
| 76 | /// collection only being checked in isolation. |
| 77 | #[derive(Debug)] |
| 78 | pub(crate) struct DecodeContext { |
| 79 | /// Bytes still available for allocations while decoding the current datum. |
| 80 | remaining_budget: usize, |
| 81 | /// Current recursion depth of `decode_internal`. |
| 82 | depth: usize, |
| 83 | } |
| 84 | |
| 85 | impl DecodeContext { |
| 86 | /// Create a new context. |
| 87 | /// |
| 88 | /// This should only be done when a new datum is being decoded, never during the decoding. |
| 89 | pub(crate) fn new() -> Self { |
| 90 | Self { |
| 91 | remaining_budget: max_allocation_bytes(DEFAULT_MAX_ALLOCATION_BYTES), |
| 92 | depth: 0, |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | /// Debit `bytes` from the per-datum allocation budget |
| 97 | /// |
| 98 | /// # Errors |
| 99 | /// `Details::MemoryAllocation` if the maximum budget is exceeded. |
| 100 | fn debit_bytes(&mut self, bytes: usize) -> AvroResult<()> { |
| 101 | match self.remaining_budget.checked_sub(bytes) { |
| 102 | Some(remaining) => { |
| 103 | self.remaining_budget = remaining; |
| 104 | Ok(()) |
| 105 | } |
| 106 | None => Err(Details::MemoryAllocation { |
| 107 | desired: Some(bytes), |
| 108 | maximum: max_allocation_bytes(DEFAULT_MAX_ALLOCATION_BYTES), |
| 109 | } |
| 110 | .into()), |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /// Debit the amount of bytes for `n` items of `T`. |
| 115 | /// |
| 116 | /// # Errors |
| 117 | /// `Details::MemoryAllocation` if the maximum budget is exceeded. |
| 118 | fn debit_items<T>(&mut self, n: usize) -> AvroResult<()> { |
| 119 | let bytes = n |
| 120 | .checked_mul(size_of::<T>()) |
| 121 | .ok_or(Details::IntegerOverflow)?; |
| 122 | self.debit_bytes(bytes) |
| 123 | } |
| 124 | |
| 125 | /// Track one level of decoding recursion, erroring once the configured |
| 126 | /// maximum depth is exceeded. |
| 127 | fn enter(&mut self) -> AvroResult<()> { |
| 128 | self.depth += 1; |
| 129 | let maximum = decode_recursion_limit(); |
| 130 | if self.depth > maximum { |
| 131 | Err(Details::DecodeRecursionLimit { maximum }.into()) |
| 132 | } else { |
| 133 | Ok(()) |
| 134 | } |
no test coverage detected