rhai/api/
limits.rs

1//! Settings for [`Engine`]'s limitations.
2#![cfg(not(feature = "unchecked"))]
3
4use crate::Engine;
5use std::num::{NonZeroU64, NonZeroUsize};
6#[cfg(feature = "no_std")]
7use std::prelude::v1::*;
8
9#[cfg(debug_assertions)]
10pub mod default_limits {
11    /// Maximum levels of function calls.
12    ///
13    /// Not available under `no_function`.
14    #[cfg(not(feature = "no_function"))]
15    pub const MAX_CALL_STACK_DEPTH: usize = 8;
16    /// Maximum levels of expressions.
17    pub const MAX_EXPR_DEPTH: usize = 32;
18    /// Maximum levels of expressions in function bodies.
19    ///
20    /// Not available under `no_function`.
21    #[cfg(not(feature = "no_function"))]
22    pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
23}
24#[cfg(not(debug_assertions))]
25pub mod default_limits {
26    /// Maximum levels of function calls.
27    ///
28    /// Not available under `no_function`.
29    #[cfg(not(feature = "no_function"))]
30    pub const MAX_CALL_STACK_DEPTH: usize = 64;
31    /// Maximum levels of expressions.
32    pub const MAX_EXPR_DEPTH: usize = 64;
33    /// Maximum levels of expressions in function bodies.
34    ///
35    /// Not available under `no_function`.
36    #[cfg(not(feature = "no_function"))]
37    pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
38}
39
40/// A type containing all the limits imposed by the [`Engine`].
41///
42/// Not available under `unchecked`.
43#[derive(Debug, Clone, Eq, PartialEq, Hash)]
44pub struct Limits {
45    /// Maximum levels of call-stack to prevent infinite recursion.
46    ///
47    /// Set to zero to effectively disable function calls.
48    ///
49    /// Not available under `no_function`.
50    #[cfg(not(feature = "no_function"))]
51    pub call_stack_depth: usize,
52    /// Maximum depth of statements/expressions at global level.
53    pub expr_depth: Option<NonZeroUsize>,
54    /// Maximum depth of statements/expressions in functions.
55    ///
56    /// Not available under `no_function`.
57    #[cfg(not(feature = "no_function"))]
58    pub function_expr_depth: Option<NonZeroUsize>,
59    /// Maximum number of operations allowed to run.
60    pub num_operations: Option<NonZeroU64>,
61    /// Maximum number of variables allowed at any instant.
62    ///
63    /// Set to zero to effectively disable creating variables.
64    pub num_variables: usize,
65    /// Maximum number of scripted functions allowed.
66    ///
67    /// Set to zero to effectively disable defining any function.
68    ///
69    /// Not available under `no_function`.
70    #[cfg(not(feature = "no_function"))]
71    pub num_functions: usize,
72    /// Maximum number of [modules][crate::Module] allowed to load.
73    ///
74    /// Set to zero to effectively disable loading any [module][crate::Module].
75    ///
76    /// Not available under `no_module`.
77    #[cfg(not(feature = "no_module"))]
78    pub num_modules: usize,
79    /// Maximum length of a [string][crate::ImmutableString].
80    pub string_len: Option<NonZeroUsize>,
81    /// Maximum length of an [array][crate::Array].
82    ///
83    /// Not available under `no_index`.
84    #[cfg(not(feature = "no_index"))]
85    pub array_size: Option<NonZeroUsize>,
86    /// Maximum number of properties in an [object map][crate::Map].
87    ///
88    /// Not available under `no_object`.
89    #[cfg(not(feature = "no_object"))]
90    pub map_size: Option<NonZeroUsize>,
91}
92
93impl Limits {
94    /// Create a new [`Limits`] with default values.
95    ///
96    /// Not available under `unchecked`.
97    #[inline]
98    pub const fn new() -> Self {
99        Self {
100            #[cfg(not(feature = "no_function"))]
101            call_stack_depth: default_limits::MAX_CALL_STACK_DEPTH,
102            expr_depth: NonZeroUsize::new(default_limits::MAX_EXPR_DEPTH),
103            #[cfg(not(feature = "no_function"))]
104            function_expr_depth: NonZeroUsize::new(default_limits::MAX_FUNCTION_EXPR_DEPTH),
105            num_operations: None,
106            num_variables: usize::MAX,
107            #[cfg(not(feature = "no_function"))]
108            num_functions: usize::MAX,
109            #[cfg(not(feature = "no_module"))]
110            num_modules: usize::MAX,
111            string_len: None,
112            #[cfg(not(feature = "no_index"))]
113            array_size: None,
114            #[cfg(not(feature = "no_object"))]
115            map_size: None,
116        }
117    }
118}
119
120impl Default for Limits {
121    #[inline(always)]
122    fn default() -> Self {
123        Self::new()
124    }
125}
126
127impl Engine {
128    /// Is there a data size limit set?
129    #[inline(always)]
130    pub(crate) const fn has_data_size_limit(&self) -> bool {
131        self.limits.string_len.is_some()
132            || {
133                #[cfg(not(feature = "no_index"))]
134                {
135                    self.limits.array_size.is_some()
136                }
137                #[cfg(feature = "no_index")]
138                false
139            }
140            || {
141                #[cfg(not(feature = "no_object"))]
142                {
143                    self.limits.map_size.is_some()
144                }
145                #[cfg(feature = "no_object")]
146                false
147            }
148    }
149    /// Set the maximum levels of function calls allowed for a script in order to avoid
150    /// infinite recursion and stack overflows.
151    ///
152    /// Not available under `unchecked` or `no_function`.
153    #[cfg(not(feature = "no_function"))]
154    #[inline(always)]
155    pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
156        self.limits.call_stack_depth = levels;
157        self
158    }
159    /// The maximum levels of function calls allowed for a script.
160    ///
161    /// Not available under `unchecked` or `no_function`.
162    #[cfg(not(feature = "no_function"))]
163    #[inline(always)]
164    #[must_use]
165    pub const fn max_call_levels(&self) -> usize {
166        self.limits.call_stack_depth
167    }
168    /// Set the maximum number of operations allowed for a script to run to avoid
169    /// consuming too much resources (0 for unlimited).
170    ///
171    /// Not available under `unchecked`.
172    #[inline(always)]
173    pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
174        self.limits.num_operations = NonZeroU64::new(operations);
175        self
176    }
177    /// The maximum number of operations allowed for a script to run (0 for unlimited).
178    ///
179    /// Not available under `unchecked`.
180    #[inline]
181    #[must_use]
182    pub const fn max_operations(&self) -> u64 {
183        match self.limits.num_operations {
184            Some(n) => n.get(),
185            None => 0,
186        }
187    }
188    /// Set the maximum number of variables allowed for a script at any instant.
189    ///
190    /// Not available under `unchecked`.
191    #[inline(always)]
192    pub fn set_max_variables(&mut self, variables: usize) -> &mut Self {
193        self.limits.num_variables = variables;
194        self
195    }
196    /// The maximum number of variables allowed for a script at any instant.
197    ///
198    /// Not available under `unchecked`.
199    #[inline(always)]
200    #[must_use]
201    pub const fn max_variables(&self) -> usize {
202        self.limits.num_variables
203    }
204    /// Set the maximum number of scripted functions allowed for a script at any instant.
205    ///
206    /// Not available under `unchecked` or `no_function`
207    #[cfg(not(feature = "no_function"))]
208    #[inline(always)]
209    pub fn set_max_functions(&mut self, functions: usize) -> &mut Self {
210        self.limits.num_functions = functions;
211        self
212    }
213    /// The maximum number of scripted functions allowed for a script at any instant.
214    ///
215    /// Not available under `unchecked` or `no_function`
216    #[cfg(not(feature = "no_function"))]
217    #[inline(always)]
218    #[must_use]
219    pub const fn max_functions(&self) -> usize {
220        self.limits.num_functions
221    }
222    /// Set the maximum number of imported [modules][crate::Module] allowed for a script.
223    ///
224    /// Not available under `unchecked` or `no_module`.
225    #[cfg(not(feature = "no_module"))]
226    #[inline(always)]
227    pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
228        self.limits.num_modules = modules;
229        self
230    }
231    /// The maximum number of imported [modules][crate::Module] allowed for a script.
232    ///
233    /// Not available under `unchecked` or `no_module`.
234    #[cfg(not(feature = "no_module"))]
235    #[inline(always)]
236    #[must_use]
237    pub const fn max_modules(&self) -> usize {
238        self.limits.num_modules
239    }
240    /// Set the depth limits for expressions (0 for unlimited).
241    ///
242    /// Not available under `unchecked`.
243    #[inline(always)]
244    pub fn set_max_expr_depths(
245        &mut self,
246        max_expr_depth: usize,
247        #[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
248    ) -> &mut Self {
249        self.limits.expr_depth = NonZeroUsize::new(max_expr_depth);
250        #[cfg(not(feature = "no_function"))]
251        {
252            self.limits.function_expr_depth = NonZeroUsize::new(max_function_expr_depth);
253        }
254        self
255    }
256    /// The depth limit for expressions (0 for unlimited).
257    ///
258    /// Not available under `unchecked`.
259    #[inline]
260    #[must_use]
261    pub const fn max_expr_depth(&self) -> usize {
262        match self.limits.expr_depth {
263            Some(n) => n.get(),
264            None => 0,
265        }
266    }
267    /// The depth limit for expressions in functions (0 for unlimited).
268    ///
269    /// Not available under `unchecked` or `no_function`.
270    #[inline]
271    #[must_use]
272    pub const fn max_function_expr_depth(&self) -> usize {
273        #[cfg(not(feature = "no_function"))]
274        return match self.limits.function_expr_depth {
275            Some(n) => n.get(),
276            None => 0,
277        };
278        #[cfg(feature = "no_function")]
279        return 0;
280    }
281    /// Set the maximum length, in bytes, of [strings][crate::ImmutableString] (0 for unlimited).
282    ///
283    /// Not available under `unchecked`.
284    #[inline(always)]
285    pub fn set_max_string_size(&mut self, max_len: usize) -> &mut Self {
286        self.limits.string_len = NonZeroUsize::new(max_len);
287        self
288    }
289    /// The maximum length, in bytes, of [strings][crate::ImmutableString] (0 for unlimited).
290    ///
291    /// Not available under `unchecked`.
292    #[inline]
293    #[must_use]
294    pub const fn max_string_size(&self) -> usize {
295        match self.limits.string_len {
296            Some(n) => n.get(),
297            None => 0,
298        }
299    }
300    /// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
301    ///
302    /// Not available under `unchecked` or `no_index`.
303    #[cfg(not(feature = "no_index"))]
304    #[inline(always)]
305    pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
306        self.limits.array_size = NonZeroUsize::new(max_size);
307        self
308    }
309    /// The maximum length of [arrays][crate::Array] (0 for unlimited).
310    ///
311    /// Not available under `unchecked` or `no_index`.
312    #[inline]
313    #[must_use]
314    pub const fn max_array_size(&self) -> usize {
315        #[cfg(not(feature = "no_index"))]
316        return match self.limits.array_size {
317            Some(n) => n.get(),
318            None => 0,
319        };
320        #[cfg(feature = "no_index")]
321        return 0;
322    }
323    /// Set the maximum size of [object maps][crate::Map] (0 for unlimited).
324    ///
325    /// Not available under `unchecked` or `no_object`.
326    #[cfg(not(feature = "no_object"))]
327    #[inline(always)]
328    pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
329        self.limits.map_size = NonZeroUsize::new(max_size);
330        self
331    }
332    /// The maximum size of [object maps][crate::Map] (0 for unlimited).
333    ///
334    /// Not available under `unchecked` or `no_object`.
335    #[inline]
336    #[must_use]
337    pub const fn max_map_size(&self) -> usize {
338        #[cfg(not(feature = "no_object"))]
339        return match self.limits.map_size {
340            Some(n) => n.get(),
341            None => 0,
342        };
343        #[cfg(feature = "no_object")]
344        return 0;
345    }
346}