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