spo_rhai/func/
function.rs

1//! Module defining the standard Rhai function type.
2
3use super::native::{FnAny, FnIterator, FnPlugin, SendSync};
4use crate::ast::{EncapsulatedEnviron, FnAccess};
5use crate::plugin::PluginFunc;
6use crate::Shared;
7use std::fmt;
8#[cfg(feature = "no_std")]
9use std::prelude::v1::*;
10
11/// _(internals)_ A type encapsulating a function callable by Rhai.
12/// Exported under the `internals` feature only.
13#[derive(Clone)]
14#[non_exhaustive]
15pub enum RhaiFunc {
16    /// A pure native Rust function with all arguments passed by value.
17    Pure {
18        /// Shared function pointer.
19        func: Shared<FnAny>,
20        /// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
21        has_context: bool,
22        /// This is a dummy field and is not used.
23        is_pure: bool,
24        /// Is this function volatile?
25        ///
26        /// A volatile function does not guarantee the same result for the same input(s).
27        is_volatile: bool,
28    },
29    /// A native Rust object method with the first argument passed by reference,
30    /// and the rest passed by value.
31    Method {
32        /// Shared function pointer.
33        func: Shared<FnAny>,
34        /// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
35        has_context: bool,
36        /// Allow operating on constants?
37        is_pure: bool,
38        /// Is this function volatile?
39        ///
40        /// A volatile function does not guarantee the same result for the same input(s).
41        is_volatile: bool,
42    },
43    /// An iterator function.
44    Iterator {
45        /// Shared function pointer.
46        func: Shared<FnIterator>,
47    },
48    /// A plugin function,
49    Plugin {
50        /// Shared function pointer.
51        func: Shared<FnPlugin>,
52    },
53    /// A script-defined function.
54    #[cfg(not(feature = "no_function"))]
55    Script {
56        /// Shared reference to the [`ScriptFuncDef`][crate::ast::ScriptFuncDef] function definition.
57        fn_def: Shared<crate::ast::ScriptFuncDef>,
58        /// Encapsulated environment, if any.
59        environ: Option<Shared<EncapsulatedEnviron>>,
60    },
61}
62
63impl fmt::Debug for RhaiFunc {
64    #[cold]
65    #[inline(never)]
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            Self::Pure { .. } => f.write_str("NativePureFunction"),
69            Self::Method { .. } => f.write_str("NativeMethod"),
70            Self::Iterator { .. } => f.write_str("NativeIterator"),
71            Self::Plugin { .. } => f.write_str("PluginFunction"),
72
73            #[cfg(not(feature = "no_function"))]
74            Self::Script { fn_def, .. } => fmt::Debug::fmt(fn_def, f),
75        }
76    }
77}
78
79impl fmt::Display for RhaiFunc {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        match self {
82            Self::Pure { .. } => f.write_str("NativePureFunction"),
83            Self::Method { .. } => f.write_str("NativeMethod"),
84            Self::Iterator { .. } => f.write_str("NativeIterator"),
85            Self::Plugin { .. } => f.write_str("PluginFunction"),
86
87            #[cfg(not(feature = "no_function"))]
88            Self::Script { fn_def, .. } => fmt::Display::fmt(fn_def, f),
89        }
90    }
91}
92
93impl RhaiFunc {
94    /// Is this a pure native Rust function?
95    #[inline]
96    #[must_use]
97    pub fn is_pure(&self) -> bool {
98        match self {
99            Self::Pure { .. } => true,
100            Self::Method { is_pure, .. } => *is_pure,
101            Self::Iterator { .. } => true,
102
103            Self::Plugin { func, .. } => func.is_pure(),
104
105            #[cfg(not(feature = "no_function"))]
106            Self::Script { .. } => false,
107        }
108    }
109    /// Is this a native Rust method function?
110    #[inline]
111    #[must_use]
112    pub fn is_method(&self) -> bool {
113        match self {
114            Self::Method { .. } => true,
115            Self::Pure { .. } | Self::Iterator { .. } => false,
116
117            Self::Plugin { func, .. } => func.is_method_call(),
118
119            #[cfg(not(feature = "no_function"))]
120            Self::Script { .. } => false,
121        }
122    }
123    /// Is this an iterator function?
124    #[inline]
125    #[must_use]
126    pub const fn is_iter(&self) -> bool {
127        match self {
128            Self::Iterator { .. } => true,
129            Self::Pure { .. } | Self::Method { .. } | Self::Plugin { .. } => false,
130
131            #[cfg(not(feature = "no_function"))]
132            Self::Script { .. } => false,
133        }
134    }
135    /// Is this a script-defined function?
136    #[inline]
137    #[must_use]
138    pub const fn is_script(&self) -> bool {
139        #[cfg(feature = "no_function")]
140        return false;
141
142        #[cfg(not(feature = "no_function"))]
143        match self {
144            Self::Script { .. } => true,
145            Self::Pure { .. }
146            | Self::Method { .. }
147            | Self::Iterator { .. }
148            | Self::Plugin { .. } => false,
149        }
150    }
151    /// Is this a plugin function?
152    #[inline]
153    #[must_use]
154    pub const fn is_plugin_fn(&self) -> bool {
155        match self {
156            Self::Plugin { .. } => true,
157            Self::Pure { .. } | Self::Method { .. } | Self::Iterator { .. } => false,
158
159            #[cfg(not(feature = "no_function"))]
160            Self::Script { .. } => false,
161        }
162    }
163    /// Is this a native Rust function?
164    #[inline]
165    #[must_use]
166    pub const fn is_native(&self) -> bool {
167        #[cfg(feature = "no_function")]
168        return true;
169
170        #[cfg(not(feature = "no_function"))]
171        match self {
172            Self::Pure { .. }
173            | Self::Method { .. }
174            | Self::Plugin { .. }
175            | Self::Iterator { .. } => true,
176            Self::Script { .. } => false,
177        }
178    }
179    /// Is there a [`NativeCallContext`][crate::NativeCallContext] parameter?
180    #[inline]
181    #[must_use]
182    pub fn has_context(&self) -> bool {
183        match self {
184            Self::Pure { has_context, .. } | Self::Method { has_context, .. } => *has_context,
185            Self::Plugin { func, .. } => func.has_context(),
186            Self::Iterator { .. } => false,
187            #[cfg(not(feature = "no_function"))]
188            Self::Script { .. } => false,
189        }
190    }
191    /// Is this function volatile?
192    ///
193    /// A volatile function does not guarantee the same result for the same input(s).
194    #[inline]
195    #[must_use]
196    pub fn is_volatile(&self) -> bool {
197        match self {
198            Self::Pure { is_volatile, .. } => *is_volatile,
199            Self::Method { is_volatile, .. } => *is_volatile,
200            Self::Iterator { .. } => true,
201
202            Self::Plugin { func, .. } => func.is_volatile(),
203
204            // Scripts are assumed to be volatile -- it can be calling volatile native functions.
205            #[cfg(not(feature = "no_function"))]
206            Self::Script { .. } => true,
207        }
208    }
209    /// Get the access mode.
210    #[inline]
211    #[must_use]
212    pub fn access(&self) -> FnAccess {
213        #[cfg(feature = "no_function")]
214        return FnAccess::Public;
215
216        #[cfg(not(feature = "no_function"))]
217        match self {
218            Self::Plugin { .. }
219            | Self::Pure { .. }
220            | Self::Method { .. }
221            | Self::Iterator { .. } => FnAccess::Public,
222            Self::Script { fn_def, .. } => fn_def.access,
223        }
224    }
225    /// Get a shared reference to a native Rust function.
226    #[inline]
227    #[must_use]
228    pub fn get_native_fn(&self) -> Option<&Shared<FnAny>> {
229        match self {
230            Self::Pure { func, .. } | Self::Method { func, .. } => Some(func),
231            Self::Iterator { .. } | Self::Plugin { .. } => None,
232
233            #[cfg(not(feature = "no_function"))]
234            Self::Script { .. } => None,
235        }
236    }
237    /// Get a shared reference to a script-defined function definition.
238    ///
239    /// Not available under `no_function`.
240    #[cfg(not(feature = "no_function"))]
241    #[inline]
242    #[must_use]
243    pub const fn get_script_fn_def(&self) -> Option<&Shared<crate::ast::ScriptFuncDef>> {
244        match self {
245            Self::Pure { .. }
246            | Self::Method { .. }
247            | Self::Iterator { .. }
248            | Self::Plugin { .. } => None,
249            Self::Script { fn_def, .. } => Some(fn_def),
250        }
251    }
252    /// Get a reference to the shared encapsulated environment of the function definition.
253    ///
254    /// Not available under `no_function` or `no_module`.
255    #[inline]
256    #[must_use]
257    pub fn get_encapsulated_environ(&self) -> Option<&EncapsulatedEnviron> {
258        match self {
259            Self::Pure { .. }
260            | Self::Method { .. }
261            | Self::Iterator { .. }
262            | Self::Plugin { .. } => None,
263
264            #[cfg(not(feature = "no_function"))]
265            Self::Script { environ, .. } => environ.as_deref(),
266        }
267    }
268    /// Get a reference to an iterator function.
269    #[inline]
270    #[must_use]
271    pub fn get_iter_fn(&self) -> Option<&FnIterator> {
272        match self {
273            Self::Iterator { func, .. } => Some(&**func),
274            Self::Pure { .. } | Self::Method { .. } | Self::Plugin { .. } => None,
275
276            #[cfg(not(feature = "no_function"))]
277            Self::Script { .. } => None,
278        }
279    }
280    /// Get a shared reference to a plugin function.
281    #[inline]
282    #[must_use]
283    pub fn get_plugin_fn(&self) -> Option<&Shared<FnPlugin>> {
284        match self {
285            Self::Plugin { func, .. } => Some(func),
286            Self::Pure { .. } | Self::Method { .. } | Self::Iterator { .. } => None,
287
288            #[cfg(not(feature = "no_function"))]
289            Self::Script { .. } => None,
290        }
291    }
292}
293
294#[cfg(not(feature = "no_function"))]
295impl From<crate::ast::ScriptFuncDef> for RhaiFunc {
296    #[inline(always)]
297    fn from(fn_def: crate::ast::ScriptFuncDef) -> Self {
298        Self::Script {
299            fn_def: fn_def.into(),
300            environ: None,
301        }
302    }
303}
304
305#[cfg(not(feature = "no_function"))]
306impl From<Shared<crate::ast::ScriptFuncDef>> for RhaiFunc {
307    #[inline(always)]
308    fn from(fn_def: Shared<crate::ast::ScriptFuncDef>) -> Self {
309        Self::Script {
310            fn_def,
311            environ: None,
312        }
313    }
314}
315
316impl<T: PluginFunc + 'static + SendSync> From<T> for RhaiFunc {
317    #[inline(always)]
318    fn from(func: T) -> Self {
319        Self::Plugin {
320            func: Shared::new(func),
321        }
322    }
323}
324
325impl From<Shared<FnPlugin>> for RhaiFunc {
326    #[inline(always)]
327    fn from(func: Shared<FnPlugin>) -> Self {
328        Self::Plugin { func }
329    }
330}