Skip to main content

sacp_cbor/
limits.rs

1use crate::{CborError, ErrorCode};
2
3/// Default maximum nesting depth limit.
4pub const DEFAULT_MAX_DEPTH: usize = 256;
5
6/// Default maximum container length limit for arrays/maps.
7///
8/// This is a safety limit; adjust explicitly for your deployment.
9pub const DEFAULT_MAX_CONTAINER_LEN: usize = 1 << 16;
10
11/// Decode-time resource limits for validation and decoding.
12///
13/// Limits are enforced deterministically and must not depend on background timers.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct DecodeLimits {
16    /// Maximum total input length in bytes.
17    pub max_input_bytes: usize,
18    /// Maximum nesting depth.
19    pub max_depth: usize,
20    /// Maximum total count of container items:
21    /// `sum(array_len) + sum(2 * map_pairs)` across the entire decoded item
22    /// (maps count both keys and values).
23    pub max_total_items: usize,
24    /// Maximum array length.
25    pub max_array_len: usize,
26    /// Maximum map length (pairs).
27    pub max_map_len: usize,
28    /// Maximum byte-string length (also applies to bignum magnitudes).
29    pub max_bytes_len: usize,
30    /// Maximum text-string length in UTF-8 bytes.
31    pub max_text_len: usize,
32}
33
34impl DecodeLimits {
35    /// Construct conservative limits derived from a maximum message size.
36    ///
37    /// The defaults are:
38    /// - `max_input_bytes = max_message_bytes`
39    /// - `max_total_items = max_message_bytes`
40    /// - `max_bytes_len = max_message_bytes`
41    /// - `max_text_len = max_message_bytes`
42    /// - `max_array_len` and `max_map_len` are capped by `DEFAULT_MAX_CONTAINER_LEN`
43    ///
44    /// This is a pragmatic baseline. Production deployments should tune these explicitly.
45    #[must_use]
46    pub fn for_bytes(max_message_bytes: usize) -> Self {
47        let max_container_len = max_message_bytes.min(DEFAULT_MAX_CONTAINER_LEN);
48        Self {
49            max_input_bytes: max_message_bytes,
50            max_depth: DEFAULT_MAX_DEPTH,
51            max_total_items: max_message_bytes,
52            max_array_len: max_container_len,
53            max_map_len: max_container_len,
54            max_bytes_len: max_message_bytes,
55            max_text_len: max_message_bytes,
56        }
57    }
58}
59
60/// End-to-end limits used by SACP implementations.
61///
62/// SACP commonly distinguishes between:
63/// - maximum message size on the wire, and
64/// - maximum size of canonical CBOR stored durably as state.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct CborLimits {
67    /// Maximum bytes per message.
68    pub max_message_bytes: usize,
69    /// Maximum bytes per state blob (must be <= `max_message_bytes`).
70    pub max_state_bytes: usize,
71}
72
73impl CborLimits {
74    /// Construct new limits.
75    ///
76    /// # Errors
77    ///
78    /// Returns `InvalidLimits` if `max_state_bytes > max_message_bytes`.
79    pub const fn new(max_message_bytes: usize, max_state_bytes: usize) -> Result<Self, CborError> {
80        if max_state_bytes > max_message_bytes {
81            return Err(CborError::new(ErrorCode::InvalidLimits, 0));
82        }
83        Ok(Self {
84            max_message_bytes,
85            max_state_bytes,
86        })
87    }
88
89    /// Decode limits appropriate for validating incoming messages.
90    #[must_use]
91    pub fn message_limits(self) -> DecodeLimits {
92        DecodeLimits::for_bytes(self.max_message_bytes)
93    }
94
95    /// Decode limits appropriate for validating stored canonical state.
96    #[must_use]
97    pub fn state_limits(self) -> DecodeLimits {
98        DecodeLimits::for_bytes(self.max_state_bytes)
99    }
100}