Skip to main content

lemma/
limits.rs

1use crate::error::Error;
2use crate::parsing::source::Source;
3
4pub const MAX_SPEC_NAME_LENGTH: usize = 128;
5pub const MAX_FACT_NAME_LENGTH: usize = 256;
6pub const MAX_RULE_NAME_LENGTH: usize = 256;
7pub const MAX_TYPE_NAME_LENGTH: usize = 256;
8
9/// Maximum significant digits in a number string. rust_decimal supports at most 28;
10/// more can panic or overflow in parse or arithmetic.
11pub const MAX_NUMBER_DIGITS: usize = 28;
12
13/// Validate that a name does not exceed the given character limit.
14/// `kind` is a human-readable noun like "spec", "fact", "rule", or "type".
15pub fn check_max_length(
16    name: &str,
17    limit: usize,
18    kind: &str,
19    source: Option<Source>,
20) -> Result<(), Error> {
21    if name.len() > limit {
22        return Err(Error::resource_limit_exceeded(
23            format!("max_{kind}_name_length"),
24            format!("{limit} characters"),
25            format!("{} characters", name.len()),
26            format!("Shorten the {kind} name to at most {limit} characters"),
27            source,
28        ));
29    }
30    Ok(())
31}
32
33/// Limits to prevent abuse and enable predictable resource usage
34///
35/// These limits protect against malicious inputs while being generous enough
36/// for all legitimate use cases.
37#[derive(Debug, Clone)]
38pub struct ResourceLimits {
39    /// Maximum file size in bytes
40    /// Real usage: ~5KB, Limit: 5MB (1000x)
41    pub max_file_size_bytes: usize,
42
43    /// Maximum expression nesting depth
44    /// Real usage: ~3 levels, Limit: 7. Deeper logic via rule composition.
45    pub max_expression_depth: usize,
46
47    /// Maximum expression nodes per file (parser-level)
48    /// Quick-reject for pathological single files.
49    pub max_expression_count: usize,
50
51    /// Maximum total expression nodes across all files (engine-level)
52    /// The real capacity ceiling. pi (~3.1M) — generous for national-scale
53    /// regulatory systems while bounding total engine workload.
54    pub max_total_expression_count: usize,
55
56    /// Maximum size of a single fact value in bytes
57    /// Real usage: ~100 bytes, Limit: 1KB (10x)
58    /// Enables server pre-allocation for zero-allocation evaluation
59    pub max_fact_value_bytes: usize,
60}
61
62impl Default for ResourceLimits {
63    fn default() -> Self {
64        Self {
65            max_file_size_bytes: 5 * 1024 * 1024, // 5 MB
66            max_expression_depth: 7,
67            max_expression_count: 4096,
68            max_total_expression_count: 3_141_592,
69            max_fact_value_bytes: 1024, // 1 KB
70        }
71    }
72}