use datavalue::{DataValue, OwnedDataValue};
const NODE: usize = size_of::<DataValue<'static>>();
pub(crate) fn exceeds(v: &OwnedDataValue, limit: usize) -> bool {
let mut budget = limit;
!charge(v, NODE, &mut budget)
}
pub(crate) fn charge(v: &OwnedDataValue, node_cost: usize, budget: &mut usize) -> bool {
let cost = node_cost
+ match v {
OwnedDataValue::String(s) => s.len(),
_ => 0,
};
if cost > *budget {
return false;
}
*budget -= cost;
match v {
OwnedDataValue::Array(items) => items.iter().all(|item| charge(item, node_cost, budget)),
OwnedDataValue::Object(pairs) => pairs.iter().all(|(k, item)| {
if k.len() > *budget {
return false;
}
*budget -= k.len();
charge(item, node_cost, budget)
}),
_ => true,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn small_values_fit_and_large_ones_do_not() {
let small = OwnedDataValue::Object(vec![("k".into(), OwnedDataValue::from("v"))]);
assert!(!exceeds(&small, 1024));
let long = OwnedDataValue::String("x".repeat(2000));
assert!(exceeds(&long, 1024));
assert!(!exceeds(&long, 4096));
}
#[test]
fn the_walk_stops_at_the_limit() {
let big = OwnedDataValue::Array((0..1_000_000).map(OwnedDataValue::from).collect());
let mut budget = 1024;
assert!(!charge(&big, NODE, &mut budget));
assert_eq!(budget, 1024 % NODE);
}
}