Skip to main content

wire/
limits.rs

1//! Configurable limits for bounded decoding.
2
3/// Limits for packet decoding.
4///
5/// These limits are enforced during decoding to prevent resource exhaustion
6/// attacks and ensure bounded memory usage.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct Limits {
9    /// Maximum packet size in bytes.
10    pub max_packet_bytes: usize,
11
12    /// Maximum number of sections in a packet.
13    pub max_sections: usize,
14
15    /// Maximum number of entities in an `ENTITY_CREATE` section.
16    pub max_entities_create: usize,
17
18    /// Maximum number of entities in an `ENTITY_UPDATE` section.
19    pub max_entities_update: usize,
20
21    /// Maximum number of entities in an `ENTITY_DESTROY` section.
22    pub max_entities_destroy: usize,
23
24    /// Maximum number of components per entity.
25    pub max_components_per_entity: usize,
26
27    /// Maximum number of fields per component.
28    pub max_fields_per_component: usize,
29}
30
31impl Default for Limits {
32    fn default() -> Self {
33        Self {
34            // 64 KB is generous for most FPS scenarios
35            max_packet_bytes: 64 * 1024,
36
37            // Typically only 3 sections (create, update, destroy)
38            max_sections: 16,
39
40            // Reasonable defaults for FPS games
41            max_entities_create: 256,
42            max_entities_update: 1024,
43            max_entities_destroy: 256,
44
45            // Typical ECS limits
46            max_components_per_entity: 64,
47            max_fields_per_component: 64,
48        }
49    }
50}
51
52impl Limits {
53    /// Creates limits suitable for testing with smaller values.
54    #[must_use]
55    pub const fn for_testing() -> Self {
56        Self {
57            max_packet_bytes: 4096,
58            max_sections: 8,
59            max_entities_create: 32,
60            max_entities_update: 64,
61            max_entities_destroy: 32,
62            max_components_per_entity: 16,
63            max_fields_per_component: 16,
64        }
65    }
66
67    /// Creates limits with no restrictions (use with caution).
68    #[must_use]
69    pub const fn unlimited() -> Self {
70        Self {
71            max_packet_bytes: usize::MAX,
72            max_sections: usize::MAX,
73            max_entities_create: usize::MAX,
74            max_entities_update: usize::MAX,
75            max_entities_destroy: usize::MAX,
76            max_components_per_entity: usize::MAX,
77            max_fields_per_component: usize::MAX,
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn default_limits_packet_bytes() {
88        let limits = Limits::default();
89        assert_eq!(limits.max_packet_bytes, 64 * 1024);
90    }
91
92    #[test]
93    fn default_limits_sections() {
94        let limits = Limits::default();
95        assert_eq!(limits.max_sections, 16);
96    }
97
98    #[test]
99    fn default_limits_entities() {
100        let limits = Limits::default();
101        assert_eq!(limits.max_entities_create, 256);
102        assert_eq!(limits.max_entities_update, 1024);
103        assert_eq!(limits.max_entities_destroy, 256);
104        // Update should be >= create (updates are more common)
105        assert!(limits.max_entities_update >= limits.max_entities_create);
106    }
107
108    #[test]
109    fn default_limits_components_fields() {
110        let limits = Limits::default();
111        assert_eq!(limits.max_components_per_entity, 64);
112        assert_eq!(limits.max_fields_per_component, 64);
113    }
114
115    #[test]
116    fn testing_limits_smaller() {
117        let test_limits = Limits::for_testing();
118        let default_limits = Limits::default();
119
120        assert!(test_limits.max_packet_bytes < default_limits.max_packet_bytes);
121        assert!(test_limits.max_sections < default_limits.max_sections);
122        assert!(test_limits.max_entities_create < default_limits.max_entities_create);
123        assert!(test_limits.max_entities_update < default_limits.max_entities_update);
124        assert!(test_limits.max_entities_destroy < default_limits.max_entities_destroy);
125    }
126
127    #[test]
128    fn testing_limits_values() {
129        let limits = Limits::for_testing();
130        assert_eq!(limits.max_packet_bytes, 4096);
131        assert_eq!(limits.max_sections, 8);
132        assert_eq!(limits.max_entities_create, 32);
133        assert_eq!(limits.max_entities_update, 64);
134        assert_eq!(limits.max_entities_destroy, 32);
135        assert_eq!(limits.max_components_per_entity, 16);
136        assert_eq!(limits.max_fields_per_component, 16);
137    }
138
139    #[test]
140    fn unlimited_limits() {
141        let limits = Limits::unlimited();
142        assert_eq!(limits.max_packet_bytes, usize::MAX);
143        assert_eq!(limits.max_sections, usize::MAX);
144        assert_eq!(limits.max_entities_create, usize::MAX);
145        assert_eq!(limits.max_entities_update, usize::MAX);
146        assert_eq!(limits.max_entities_destroy, usize::MAX);
147        assert_eq!(limits.max_components_per_entity, usize::MAX);
148        assert_eq!(limits.max_fields_per_component, usize::MAX);
149    }
150
151    #[test]
152    fn limits_equality() {
153        let l1 = Limits::default();
154        let l2 = Limits::default();
155        let l3 = Limits::for_testing();
156
157        assert_eq!(l1, l2);
158        assert_ne!(l1, l3);
159    }
160
161    #[test]
162    fn limits_clone() {
163        let limits = Limits::default();
164        let cloned = limits.clone();
165        assert_eq!(limits, cloned);
166    }
167
168    #[test]
169    fn limits_debug() {
170        let limits = Limits::default();
171        let debug = format!("{limits:?}");
172        assert!(debug.contains("Limits"));
173        assert!(debug.contains("max_packet_bytes"));
174    }
175
176    #[test]
177    fn limits_const_constructible() {
178        const LIMITS: Limits = Limits::for_testing();
179        assert_eq!(LIMITS.max_packet_bytes, 4096);
180    }
181}