rhai/api/
register.rs

1//! Module that defines the public function/module registration API of [`Engine`].
2
3use crate::func::{FnCallArgs, RhaiFunc, RhaiNativeFunc, SendSync};
4use crate::module::FuncRegistration;
5use crate::types::dynamic::Variant;
6use crate::{
7    Dynamic, Engine, Identifier, Module, NativeCallContext, RhaiResultOf, Shared, SharedModule,
8};
9use std::any::{type_name, TypeId};
10#[cfg(feature = "no_std")]
11use std::prelude::v1::*;
12
13#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
14use crate::func::register::Mut;
15
16impl Engine {
17    /// Get a mutable reference to the global namespace module
18    /// (which is the first module in `global_modules`).
19    #[inline(always)]
20    #[must_use]
21    pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
22        if self.global_modules.is_empty() {
23            let mut global_namespace = Module::new();
24            global_namespace.set_internal(true);
25            self.global_modules.push(global_namespace.into());
26        }
27
28        Shared::get_mut(self.global_modules.first_mut().unwrap()).unwrap()
29    }
30    /// Register a custom function with the [`Engine`].
31    ///
32    /// # Assumptions
33    ///
34    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`][`crate::FnNamespace::Global`].
35    ///
36    /// * **Purity**: The function is assumed to be _pure_ unless it is a property setter or an index setter.
37    ///
38    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
39    ///
40    /// # Example
41    ///
42    /// ```
43    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
44    /// use rhai::Engine;
45    ///
46    /// // Normal function
47    /// fn add(x: i64, y: i64) -> i64 {
48    ///     x + y
49    /// }
50    ///
51    /// let mut engine = Engine::new();
52    ///
53    /// engine.register_fn("add", add);
54    ///
55    /// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
56    ///
57    /// // You can also register a closure.
58    /// engine.register_fn("sub", |x: i64, y: i64| x - y );
59    ///
60    /// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
61    /// # Ok(())
62    /// # }
63    /// ```
64    #[inline]
65    pub fn register_fn<
66        A: 'static,
67        const N: usize,
68        const X: bool,
69        R: Variant + Clone,
70        const F: bool,
71    >(
72        &mut self,
73        name: impl AsRef<str> + Into<Identifier>,
74        func: impl RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
75    ) -> &mut Self {
76        FuncRegistration::new(name.into()).register_into_engine(self, func);
77
78        self
79    }
80    /// Register a function of the [`Engine`].
81    ///
82    /// # WARNING - Low Level API
83    ///
84    /// This function is very low level.  It takes a list of [`TypeId`][std::any::TypeId]'s
85    /// indicating the actual types of the parameters.
86    ///
87    /// # Arguments
88    ///
89    /// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic].
90    /// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
91    ///
92    /// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
93    ///
94    /// To access an argument value and avoid cloning, use `args[n].take().cast::<T>()`.
95    /// Notice that this will _consume_ the argument, replacing it with `()`.
96    ///
97    /// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
98    #[inline(always)]
99    pub fn register_raw_fn<T: Variant + Clone>(
100        &mut self,
101        name: impl AsRef<str> + Into<Identifier>,
102        arg_types: impl AsRef<[TypeId]>,
103        func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf<T> + SendSync + 'static,
104    ) -> &mut Self {
105        let name = name.into();
106        let arg_types = arg_types.as_ref();
107        let is_pure = true;
108
109        #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
110        let is_pure = is_pure && (arg_types.len() != 3 || name != crate::engine::FN_IDX_SET);
111        #[cfg(not(feature = "no_object"))]
112        let is_pure = is_pure && (arg_types.len() != 2 || !name.starts_with(crate::engine::FN_SET));
113
114        FuncRegistration::new(name)
115            .in_global_namespace()
116            .set_into_module_raw(
117                self.global_namespace_mut(),
118                arg_types,
119                RhaiFunc::Method {
120                    func: Shared::new(
121                        move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
122                            func(ctx.unwrap(), args).map(Dynamic::from)
123                        },
124                    ),
125                    has_context: true,
126                    is_pure,
127                    is_volatile: true,
128                },
129            );
130
131        self
132    }
133    /// Register a custom type for use with the [`Engine`].
134    /// The type must implement [`Clone`].
135    ///
136    /// # Example
137    ///
138    /// ```
139    /// #[derive(Debug, Clone, Eq, PartialEq)]
140    /// struct TestStruct {
141    ///     field: i64
142    /// }
143    ///
144    /// impl TestStruct {
145    ///     fn new() -> Self {
146    ///         Self { field: 1 }
147    ///     }
148    ///     fn update(&mut self, offset: i64) {
149    ///         self.field += offset;
150    ///     }
151    /// }
152    ///
153    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
154    /// use rhai::Engine;
155    ///
156    /// let mut engine = Engine::new();
157    ///
158    /// // Register API for the custom type.
159    /// engine
160    ///     .register_type::<TestStruct>()
161    ///     .register_fn("new_ts", TestStruct::new)
162    ///     // Use `register_fn` to register methods on the type.
163    ///     .register_fn("update", TestStruct::update);
164    ///
165    /// # #[cfg(not(feature = "no_object"))]
166    /// assert_eq!(
167    ///     engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
168    ///     TestStruct { field: 42 }
169    /// );
170    /// # Ok(())
171    /// # }
172    /// ```
173    #[inline(always)]
174    pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
175        self.register_type_with_name::<T>(type_name::<T>())
176    }
177    /// Register a custom type for use with the [`Engine`], with a pretty-print name
178    /// for the `type_of` function. The type must implement [`Clone`].
179    ///
180    /// # Example
181    ///
182    /// ```
183    /// #[derive(Clone)]
184    /// struct TestStruct {
185    ///     field: i64
186    /// }
187    ///
188    /// impl TestStruct {
189    ///     fn new() -> Self {
190    ///         Self { field: 1 }
191    ///     }
192    /// }
193    ///
194    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
195    /// use rhai::Engine;
196    ///
197    /// let mut engine = Engine::new();
198    ///
199    /// // Register API for the custom type.
200    /// engine
201    ///     .register_type::<TestStruct>()
202    ///     .register_fn("new_ts", TestStruct::new);
203    ///
204    /// assert_eq!(
205    ///     engine.eval::<String>("let x = new_ts(); type_of(x)")?,
206    ///     "rust_out::TestStruct"
207    /// );
208    ///
209    /// // Re-register the custom type with a name.
210    /// engine.register_type_with_name::<TestStruct>("Hello");
211    ///
212    /// assert_eq!(
213    ///     engine.eval::<String>("let x = new_ts(); type_of(x)")?,
214    ///     "Hello"
215    /// );
216    /// # Ok(())
217    /// # }
218    /// ```
219    #[inline(always)]
220    pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
221        self.global_namespace_mut().set_custom_type::<T>(name);
222        self
223    }
224    /// Register a custom type for use with the [`Engine`], with a pretty-print name
225    /// for the `type_of` function. The type must implement [`Clone`].
226    ///
227    /// # WARNING - Low Level API
228    ///
229    /// This function is low level.
230    #[inline(always)]
231    pub fn register_type_with_name_raw(
232        &mut self,
233        type_path: impl Into<Identifier>,
234        name: impl Into<Identifier>,
235    ) -> &mut Self {
236        // Add the pretty-print type name into the map
237        self.global_namespace_mut()
238            .set_custom_type_raw(type_path, name);
239        self
240    }
241    /// Register a type iterator for an iterable type with the [`Engine`].
242    /// This is an advanced API.
243    #[inline(always)]
244    pub fn register_iterator<T>(&mut self) -> &mut Self
245    where
246        T: Variant + Clone + IntoIterator,
247        <T as IntoIterator>::Item: Variant + Clone,
248    {
249        self.global_namespace_mut().set_iterable::<T>();
250        self
251    }
252    /// Register a fallible type iterator for an iterable type with the [`Engine`].
253    /// This is an advanced API.
254    #[inline(always)]
255    pub fn register_iterator_result<T, R>(&mut self) -> &mut Self
256    where
257        T: Variant + Clone + IntoIterator<Item = RhaiResultOf<R>>,
258        R: Variant + Clone,
259    {
260        self.global_namespace_mut().set_iterable_result::<T, R>();
261        self
262    }
263    /// Register a getter function for a member of a registered type with the [`Engine`].
264    ///
265    /// The function signature must start with `&mut self` and not `&self`.
266    ///
267    /// Not available under `no_object`.
268    ///
269    /// # Example
270    ///
271    /// ```
272    /// #[derive(Clone)]
273    /// struct TestStruct {
274    ///     field: i64
275    /// }
276    ///
277    /// impl TestStruct {
278    ///     fn new() -> Self {
279    ///         Self { field: 1 }
280    ///     }
281    ///     // Even a getter must start with `&mut self` and not `&self`.
282    ///     fn get_field(&mut self) -> i64  {
283    ///         self.field
284    ///     }
285    /// }
286    ///
287    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
288    /// use rhai::Engine;
289    ///
290    /// let mut engine = Engine::new();
291    ///
292    /// // Register API for the custom type.
293    /// engine
294    ///     .register_type::<TestStruct>()
295    ///     .register_fn("new_ts", TestStruct::new)
296    ///     // Register a getter on a property (notice it doesn't have to be the same name).
297    ///     .register_get("xyz", TestStruct::get_field);
298    ///
299    /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
300    /// # Ok(())
301    /// # }
302    /// ```
303    #[cfg(not(feature = "no_object"))]
304    #[inline(always)]
305    pub fn register_get<T: Variant + Clone, const X: bool, R: Variant + Clone, const F: bool>(
306        &mut self,
307        name: impl AsRef<str>,
308        get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, F> + SendSync + 'static,
309    ) -> &mut Self {
310        self.register_fn(crate::engine::make_getter(name.as_ref()), get_fn)
311    }
312
313    /// Register a setter function for a member of a registered type with the [`Engine`].
314    ///
315    /// Not available under `no_object`.
316    ///
317    /// # Example
318    ///
319    /// ```
320    /// #[derive(Debug, Clone, Eq, PartialEq)]
321    /// struct TestStruct {
322    ///     field: i64
323    /// }
324    ///
325    /// impl TestStruct {
326    ///     fn new() -> Self {
327    ///         Self { field: 1 }
328    ///     }
329    ///     fn set_field(&mut self, new_val: i64) {
330    ///         self.field = new_val;
331    ///     }
332    /// }
333    ///
334    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
335    /// use rhai::Engine;
336    ///
337    /// let mut engine = Engine::new();
338    ///
339    /// // Register API for the custom type.
340    /// engine
341    ///     .register_type::<TestStruct>()
342    ///     .register_fn("new_ts", TestStruct::new)
343    ///     // Register a setter on a property (notice it doesn't have to be the same name)
344    ///     .register_set("xyz", TestStruct::set_field);
345    ///
346    /// // Notice that, with a getter, there is no way to get the property value
347    /// assert_eq!(
348    ///     engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
349    ///     TestStruct { field: 42 }
350    /// );
351    /// # Ok(())
352    /// # }
353    /// ```
354    #[cfg(not(feature = "no_object"))]
355    #[inline(always)]
356    pub fn register_set<T: Variant + Clone, const X: bool, R: Variant + Clone, const F: bool>(
357        &mut self,
358        name: impl AsRef<str>,
359        set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X, (), F> + SendSync + 'static,
360    ) -> &mut Self {
361        self.register_fn(crate::engine::make_setter(name.as_ref()), set_fn)
362    }
363    /// Short-hand for registering both getter and setter functions
364    /// of a registered type with the [`Engine`].
365    ///
366    /// All function signatures must start with `&mut self` and not `&self`.
367    ///
368    /// Not available under `no_object`.
369    ///
370    /// # Example
371    ///
372    /// ```
373    /// #[derive(Clone)]
374    /// struct TestStruct {
375    ///     field: i64
376    /// }
377    ///
378    /// impl TestStruct {
379    ///     fn new() -> Self {
380    ///         Self { field: 1 }
381    ///     }
382    ///     // Even a getter must start with `&mut self` and not `&self`.
383    ///     fn get_field(&mut self) -> i64 {
384    ///         self.field
385    ///     }
386    ///     fn set_field(&mut self, new_val: i64) {
387    ///         self.field = new_val;
388    ///     }
389    /// }
390    ///
391    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
392    /// use rhai::Engine;
393    ///
394    /// let mut engine = Engine::new();
395    ///
396    /// // Register API for the custom type.
397    /// engine
398    ///     .register_type::<TestStruct>()
399    ///     .register_fn("new_ts", TestStruct::new)
400    ///     // Register both a getter and a setter on a property
401    ///     // (notice it doesn't have to be the same name)
402    ///     .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
403    ///
404    /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
405    /// # Ok(())
406    /// # }
407    /// ```
408    #[cfg(not(feature = "no_object"))]
409    #[inline(always)]
410    pub fn register_get_set<
411        T: Variant + Clone,
412        const X1: bool,
413        const X2: bool,
414        R: Variant + Clone,
415        const F1: bool,
416        const F2: bool,
417    >(
418        &mut self,
419        name: impl AsRef<str>,
420        get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X1, R, F1> + SendSync + 'static,
421        set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X2, (), F2> + SendSync + 'static,
422    ) -> &mut Self {
423        self.register_get(&name, get_fn).register_set(&name, set_fn)
424    }
425    /// Register an index getter for a custom type with the [`Engine`].
426    ///
427    /// The function signature must start with `&mut self` and not `&self`.
428    ///
429    /// Not available under both `no_index` and `no_object`.
430    ///
431    /// # Panics
432    ///
433    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
434    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
435    /// Indexers for arrays, object maps, strings and integers cannot be registered.
436    ///
437    /// # Example
438    ///
439    /// ```
440    /// #[derive(Clone)]
441    /// struct TestStruct {
442    ///     fields: Vec<i64>
443    /// }
444    ///
445    /// impl TestStruct {
446    ///     fn new() -> Self {
447    ///         Self { fields: vec![1, 2, 3, 4, 5] }
448    ///     }
449    ///     // Even a getter must start with `&mut self` and not `&self`.
450    ///     fn get_field(&mut self, index: i64) -> i64 {
451    ///         self.fields[index as usize]
452    ///     }
453    /// }
454    ///
455    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
456    /// use rhai::Engine;
457    ///
458    /// let mut engine = Engine::new();
459    ///
460    /// // Register API for the custom type.
461    /// # #[cfg(not(feature = "no_object"))]
462    /// engine.register_type::<TestStruct>();
463    ///
464    /// engine
465    ///     .register_fn("new_ts", TestStruct::new)
466    ///     // Register an indexer.
467    ///     .register_indexer_get(TestStruct::get_field);
468    ///
469    /// # #[cfg(not(feature = "no_index"))]
470    /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
471    /// # Ok(())
472    /// # }
473    /// ```
474    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
475    #[inline(always)]
476    pub fn register_indexer_get<
477        T: Variant + Clone,
478        IDX: Variant + Clone,
479        const X: bool,
480        R: Variant + Clone,
481        const F: bool,
482    >(
483        &mut self,
484        get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X, R, F> + SendSync + 'static,
485    ) -> &mut Self {
486        self.register_fn(crate::engine::FN_IDX_GET, get_fn)
487    }
488    /// Register an index setter for a custom type with the [`Engine`].
489    ///
490    /// Not available under both `no_index` and `no_object`.
491    ///
492    /// # Panics
493    ///
494    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
495    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
496    /// Indexers for arrays, object maps, strings and integers cannot be registered.
497    ///
498    /// # Example
499    ///
500    /// ```
501    /// #[derive(Clone)]
502    /// struct TestStruct {
503    ///     fields: Vec<i64>
504    /// }
505    ///
506    /// impl TestStruct {
507    ///     fn new() -> Self {
508    ///         Self { fields: vec![1, 2, 3, 4, 5] }
509    ///     }
510    ///     fn set_field(&mut self, index: i64, value: i64) {
511    ///         self.fields[index as usize] = value;
512    ///     }
513    /// }
514    ///
515    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
516    /// use rhai::Engine;
517    ///
518    /// let mut engine = Engine::new();
519    ///
520    /// // Register API for the custom type.
521    /// # #[cfg(not(feature = "no_object"))]
522    /// engine.register_type::<TestStruct>();
523    ///
524    /// engine
525    ///     .register_fn("new_ts", TestStruct::new)
526    ///     // Register an indexer.
527    ///     .register_indexer_set(TestStruct::set_field);
528    ///
529    /// # #[cfg(not(feature = "no_index"))]
530    /// let result = engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?;
531    ///
532    /// # #[cfg(not(feature = "no_index"))]
533    /// assert_eq!(result.fields[2], 42);
534    /// # Ok(())
535    /// # }
536    /// ```
537    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
538    #[inline(always)]
539    pub fn register_indexer_set<
540        T: Variant + Clone,
541        IDX: Variant + Clone,
542        const X: bool,
543        R: Variant + Clone,
544        const F: bool,
545    >(
546        &mut self,
547        set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X, (), F> + SendSync + 'static,
548    ) -> &mut Self {
549        self.register_fn(crate::engine::FN_IDX_SET, set_fn)
550    }
551    /// Short-hand for registering both index getter and setter functions for a custom type with the [`Engine`].
552    ///
553    /// Not available under both `no_index` and `no_object`.
554    ///
555    /// # Panics
556    ///
557    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
558    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
559    /// Indexers for arrays, object maps, strings and integers cannot be registered.
560    ///
561    /// # Example
562    ///
563    /// ```
564    /// #[derive(Clone)]
565    /// struct TestStruct {
566    ///     fields: Vec<i64>
567    /// }
568    ///
569    /// impl TestStruct {
570    ///     fn new() -> Self {
571    ///         Self { fields: vec![1, 2, 3, 4, 5] }
572    ///     }
573    ///     // Even a getter must start with `&mut self` and not `&self`.
574    ///     fn get_field(&mut self, index: i64) -> i64 {
575    ///         self.fields[index as usize]
576    ///     }
577    ///     fn set_field(&mut self, index: i64, value: i64) {
578    ///         self.fields[index as usize] = value;
579    ///     }
580    /// }
581    ///
582    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
583    /// use rhai::Engine;
584    ///
585    /// let mut engine = Engine::new();
586    ///
587    /// // Register API for the custom type.
588    /// # #[cfg(not(feature = "no_object"))]
589    /// engine.register_type::<TestStruct>();
590    ///
591    /// engine
592    ///     .register_fn("new_ts", TestStruct::new)
593    ///     // Register an indexer.
594    ///     .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
595    ///
596    /// # #[cfg(not(feature = "no_index"))]
597    /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2] = 42; a[2]")?, 42);
598    /// # Ok(())
599    /// # }
600    /// ```
601    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
602    #[inline(always)]
603    pub fn register_indexer_get_set<
604        T: Variant + Clone,
605        IDX: Variant + Clone,
606        const X1: bool,
607        const X2: bool,
608        R: Variant + Clone,
609        const F1: bool,
610        const F2: bool,
611    >(
612        &mut self,
613        get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X1, R, F1> + SendSync + 'static,
614        set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X2, (), F2> + SendSync + 'static,
615    ) -> &mut Self {
616        self.register_indexer_get(get_fn)
617            .register_indexer_set(set_fn)
618    }
619    /// Register a shared [`Module`] into the global namespace of [`Engine`].
620    ///
621    /// All functions and type iterators are automatically available to scripts without namespace
622    /// qualifications.
623    ///
624    /// Sub-modules and variables are **ignored**.
625    ///
626    /// When searching for functions, modules loaded later are preferred. In other words, loaded
627    /// modules are searched in reverse order.
628    #[inline(always)]
629    pub fn register_global_module(&mut self, module: SharedModule) -> &mut Self {
630        // Make sure the global namespace is created.
631        let _ = self.global_namespace_mut();
632
633        // Insert the module into the front.
634        // The first module is always the global namespace.
635        self.global_modules.insert(1, module);
636        self
637    }
638    /// Register a shared [`Module`] as a static module namespace with the [`Engine`].
639    ///
640    /// Functions marked [`FnNamespace::Global`][`crate::FnNamespace::Global`] and type iterators are exposed to scripts without
641    /// namespace qualifications.
642    ///
643    /// Not available under `no_module`.
644    ///
645    /// # Example
646    ///
647    /// ```
648    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
649    /// use rhai::{Engine, Shared, Module};
650    ///
651    /// let mut engine = Engine::new();
652    ///
653    /// // Create the module
654    /// let mut module = Module::new();
655    /// module.set_native_fn("calc", |x: i64| Ok(x + 1));
656    ///
657    /// let module: Shared<Module> = module.into();
658    ///
659    /// engine
660    ///     // Register the module as a fixed sub-module
661    ///     .register_static_module("foo::bar::baz", module.clone())
662    ///     // Multiple registrations to the same partial path is also OK!
663    ///     .register_static_module("foo::bar::hello", module.clone())
664    ///     .register_static_module("CalcService", module);
665    ///
666    /// assert_eq!(engine.eval::<i64>("foo::bar::baz::calc(41)")?, 42);
667    /// assert_eq!(engine.eval::<i64>("foo::bar::hello::calc(41)")?, 42);
668    /// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
669    /// # Ok(())
670    /// # }
671    /// ```
672    #[cfg(not(feature = "no_module"))]
673    pub fn register_static_module(
674        &mut self,
675        name: impl AsRef<str>,
676        module: SharedModule,
677    ) -> &mut Self {
678        use std::collections::BTreeMap;
679
680        fn register_static_module_raw(
681            root: &mut BTreeMap<Identifier, SharedModule>,
682            name: &str,
683            module: SharedModule,
684        ) {
685            let separator = crate::engine::NAMESPACE_SEPARATOR;
686
687            if let Some((top_namespace, remainder)) = name
688                .split_once(separator)
689                .map(|(a, b)| (a.trim(), b.trim()))
690            {
691                let mut m = if root.is_empty() || !root.contains_key(top_namespace) {
692                    Module::new()
693                } else {
694                    crate::func::shared_take_or_clone(root.remove(top_namespace).unwrap())
695                };
696                register_static_module_raw(m.get_sub_modules_mut(), remainder, module);
697                m.build_index();
698                if m.id().is_none() {
699                    m.set_id(top_namespace);
700                }
701                root.insert(top_namespace.into(), m.into());
702            } else if module.is_indexed() {
703                let module = if module.id().is_none() {
704                    // Make a clone copy if the module does not have an ID
705                    let mut m = crate::func::shared_take_or_clone(module);
706                    m.set_id(name);
707                    m.into()
708                } else {
709                    module
710                };
711                root.insert(name.into(), module);
712            } else {
713                // Index the module (making a clone copy if necessary) if it is not indexed
714                let mut module = crate::func::shared_take_or_clone(module);
715                module.build_index();
716                if module.id().is_none() {
717                    module.set_id(name);
718                }
719                root.insert(name.into(), module.into());
720            }
721        }
722
723        register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
724        self
725    }
726    /// _(metadata)_ Generate a list of all registered functions.
727    /// Exported under the `metadata` feature only.
728    ///
729    /// Functions from the following sources are included, in order:
730    /// 1) Functions registered into the global namespace
731    /// 2) Functions in registered sub-modules
732    /// 3) Functions in registered packages
733    /// 4) Functions in standard packages (optional)
734    #[cfg(feature = "metadata")]
735    #[inline]
736    #[must_use]
737    pub fn gen_fn_signatures(&self, include_standard_packages: bool) -> Vec<String> {
738        let mut signatures = Vec::with_capacity(64);
739
740        if let Some(global_namespace) = self.global_modules.first() {
741            signatures.extend(
742                global_namespace.gen_fn_signatures_with_mapper(|s| self.format_param_type(s)),
743            );
744        }
745
746        #[cfg(not(feature = "no_module"))]
747        for (name, m) in &self.global_sub_modules {
748            signatures.extend(
749                m.gen_fn_signatures_with_mapper(|s| self.format_param_type(s))
750                    .map(|f| format!("{name}::{f}")),
751            );
752        }
753
754        signatures.extend(
755            self.global_modules
756                .iter()
757                .skip(1)
758                .filter(|m| include_standard_packages || !m.is_standard_lib())
759                .flat_map(|m| m.gen_fn_signatures_with_mapper(|s| self.format_param_type(s))),
760        );
761
762        signatures
763    }
764
765    /// Collect the [`FuncInfo`][crate::module::FuncInfo] of all functions, native or script-defined,
766    /// mapping them into any type.
767    /// Exported under the `internals` feature only.
768    ///
769    /// Return [`None`] from the `mapper` to skip a function.
770    ///
771    /// Functions from the following sources are included, in order:
772    /// 1) Functions defined in the current script (if any)
773    /// 2) Functions registered into the global namespace
774    /// 3) Functions in registered packages
775    /// 4) Functions in standard packages (optional)
776    /// 5) Functions defined in modules `import`-ed by the current script (if any)
777    /// 6) Functions in registered sub-modules
778    #[cfg(feature = "internals")]
779    #[inline(always)]
780    pub fn collect_fn_metadata<T>(
781        &self,
782        ctx: Option<&NativeCallContext>,
783        mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
784        include_standard_packages: bool,
785    ) -> Vec<T> {
786        self.collect_fn_metadata_impl(ctx, mapper, include_standard_packages)
787    }
788
789    /// Collect the [`FuncInfo`][crate::module::FuncInfo] of all functions, native or script-defined,
790    /// mapping them into any type.
791    ///
792    /// Return [`None`] from the `mapper` to skip a function.
793    ///
794    /// Functions from the following sources are included, in order:
795    /// 1) Functions defined in the current script (if any)
796    /// 2) Functions registered into the global namespace
797    /// 3) Functions in registered packages
798    /// 4) Functions in standard packages (optional)
799    /// 5) Functions defined in modules `import`-ed by the current script (if any)
800    /// 6) Functions in registered sub-modules
801    #[allow(dead_code)]
802    pub(crate) fn collect_fn_metadata_impl<T>(
803        &self,
804        _ctx: Option<&NativeCallContext>,
805        mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
806        include_standard_packages: bool,
807    ) -> Vec<T> {
808        let mut list = Vec::new();
809
810        #[cfg(not(feature = "no_function"))]
811        if let Some(ctx) = _ctx {
812            ctx.iter_namespaces()
813                .flat_map(Module::iter_fn)
814                .filter_map(|(func, f)| {
815                    mapper(crate::module::FuncInfo {
816                        metadata: f,
817                        #[cfg(not(feature = "no_module"))]
818                        namespace: Identifier::new_const(),
819                        script: func.get_script_fn_def().map(|f| (&**f).into()),
820                    })
821                })
822                .for_each(|v| list.push(v));
823        }
824
825        self.global_modules
826            .iter()
827            .filter(|m| include_standard_packages || !m.is_standard_lib())
828            .flat_map(|m| m.iter_fn())
829            .filter_map(|(_func, f)| {
830                mapper(crate::module::FuncInfo {
831                    metadata: f,
832                    #[cfg(not(feature = "no_module"))]
833                    namespace: Identifier::new_const(),
834                    #[cfg(not(feature = "no_function"))]
835                    script: _func.get_script_fn_def().map(|f| (&**f).into()),
836                })
837            })
838            .for_each(|v| list.push(v));
839
840        #[cfg(not(feature = "no_module"))]
841        {
842            // Recursively scan modules for script-defined functions.
843            fn scan_module_recursive<T>(
844                list: &mut Vec<T>,
845                namespace: &str,
846                module: &Module,
847                mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
848            ) {
849                use crate::engine::NAMESPACE_SEPARATOR;
850                use crate::SmartString;
851
852                module
853                    .iter_fn()
854                    .filter_map(|(_func, f)| {
855                        mapper(crate::module::FuncInfo {
856                            metadata: f,
857                            namespace: namespace.into(),
858                            #[cfg(not(feature = "no_function"))]
859                            script: _func.get_script_fn_def().map(|f| (&**f).into()),
860                        })
861                    })
862                    .for_each(|v| list.push(v));
863
864                module.iter_sub_modules().for_each(|(name, m)| {
865                    use std::fmt::Write;
866                    let mut ns = SmartString::new_const();
867                    write!(&mut ns, "{namespace}{NAMESPACE_SEPARATOR}{name}").unwrap();
868                    scan_module_recursive(list, &ns, m, mapper);
869                });
870            }
871
872            if let Some(ctx) = _ctx {
873                ctx.global_runtime_state()
874                    .iter_imports_raw()
875                    .for_each(|(ns, m)| scan_module_recursive(&mut list, ns, m, mapper));
876            }
877
878            self.global_sub_modules
879                .iter()
880                .for_each(|(name, m)| scan_module_recursive(&mut list, name, m, mapper));
881        }
882
883        list
884    }
885}