Skip to main content

eui_core/
limits.rs

1//! VAPP-103: the input LIMITS (`catalog/limits.json`, generated as
2//! `LIMIT_NAMES`/`LIMIT_VALUES`): an agent's input past one is refused with
3//! an issue, never worked on. Mirrors `src/limits.ts`; the issue messages
4//! are byte-identical in every core.
5
6use crate::generated::catalog as g;
7
8/// A limit by name (`maxDepth`, `maxMessageBytes`, …).
9pub fn limit(name: &str) -> Option<usize> {
10    let i = g::LIMIT_NAMES.iter().position(|n| *n == name)?;
11    g::LIMIT_VALUES.get(i)?.parse().ok()
12}
13
14/// Nodes the reducer places in one surface's tree (template nodes
15/// included), and nodes one layout build holds: the reduced tree's plus
16/// every template item's subtree.
17pub const MAX_COMPONENTS: usize = 20_000;
18/// Nesting levels of the REDUCED tree, after macro expansion (the root =
19/// 1): every reduced tree stays inside serde_json's 128-level recursion
20/// limit (2 JSON levels per node). The stack is never the bound: the
21/// recursive passes grow it on the heap (`crate::roomy`/`crate::deep`;
22/// `tests/robustness.rs` lays a 48-level surface out on a 128 KB thread).
23pub const MAX_DEPTH: usize = 48;
24/// One server message as UTF-8 JSON.
25pub const MAX_MESSAGE_BYTES: usize = 4_194_304;
26/// Template items one surface instantiates.
27pub const MAX_TEMPLATE_ITEMS: usize = 10_000;
28/// A data pointer's length in UTF-8 bytes.
29pub const MAX_POINTER_BYTES: usize = 1024;
30/// A data pointer's token count.
31pub const MAX_POINTER_SEGMENTS: usize = 64;
32
33/// An id placed a second time (two parents, or one parent twice).
34pub const USED_TWICE_ISSUE: &str = "id used twice; only its first place renders";
35
36pub fn depth_issue() -> String {
37    format!("nesting deeper than {MAX_DEPTH} levels")
38}
39
40pub fn components_issue() -> String {
41    format!("surface: more than {MAX_COMPONENTS} components; the rest is dropped")
42}
43
44pub fn template_items_issue() -> String {
45    format!("template: more than {MAX_TEMPLATE_ITEMS} items; the rest is not rendered")
46}
47
48pub fn message_bytes_issue() -> String {
49    format!("message larger than {MAX_MESSAGE_BYTES} bytes")
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn the_constants_are_limits_json() {
58        for (name, v) in [
59            ("maxComponents", MAX_COMPONENTS),
60            ("maxDepth", MAX_DEPTH),
61            ("maxMessageBytes", MAX_MESSAGE_BYTES),
62            ("maxTemplateItems", MAX_TEMPLATE_ITEMS),
63            ("maxPointerBytes", MAX_POINTER_BYTES),
64            ("maxPointerSegments", MAX_POINTER_SEGMENTS),
65        ] {
66            assert_eq!(limit(name), Some(v), "{name}");
67        }
68        assert_eq!(g::LIMIT_NAMES.len(), 6);
69    }
70}