#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limits {
pub max_depth: usize,
pub max_items: usize,
pub max_string_bytes: usize,
pub max_object_keys: usize,
}
impl Limits {
pub const MAX_DEPTH: usize = 256;
pub const DEFAULT: Self = Self {
max_depth: 64,
max_items: 10_000,
max_string_bytes: 1 << 20,
max_object_keys: 1_000,
};
pub const PERMISSIVE: Self = Self {
max_depth: 256,
max_items: usize::MAX,
max_string_bytes: usize::MAX,
max_object_keys: usize::MAX,
};
}
impl Limits {
#[must_use]
pub const fn clamped(self) -> Self {
Self {
max_depth: if self.max_depth > Self::MAX_DEPTH {
Self::MAX_DEPTH
} else {
self.max_depth
},
..self
}
}
}
const _: () = assert!(Limits::DEFAULT.max_depth <= Limits::MAX_DEPTH);
const _: () = assert!(Limits::PERMISSIVE.max_depth <= Limits::MAX_DEPTH);
impl Default for Limits {
fn default() -> Self {
Self::DEFAULT
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn max_depth_is_capped_however_it_arrives() {
let reckless = Limits { max_depth: 1_000_000, ..Limits::DEFAULT };
assert_eq!(reckless.clamped().max_depth, Limits::MAX_DEPTH);
assert_eq!(reckless.clamped().max_items, Limits::DEFAULT.max_items);
let tight = Limits { max_depth: 4, ..Limits::DEFAULT };
assert_eq!(tight.clamped().max_depth, 4);
}
#[test]
fn the_default_is_the_conservative_one() {
assert_eq!(Limits::default(), Limits::DEFAULT);
assert_eq!(
Limits::DEFAULT.max_items.min(Limits::PERMISSIVE.max_items),
Limits::DEFAULT.max_items
);
}
}