spo_rhai/module/
mod.rs

1//! Module defining external-loaded modules for Rhai.
2
3#[cfg(feature = "metadata")]
4use crate::api::formatting::format_param_type_for_display;
5use crate::ast::FnAccess;
6use crate::func::{
7    shared_take_or_clone, FnIterator, RhaiFunc, RhaiNativeFunc, SendSync, StraightHashMap,
8};
9use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypeInfo, CustomTypesCollection};
10use crate::{
11    calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnArgsVec, Identifier, ImmutableString,
12    RhaiResultOf, Shared, SharedModule, SmartString,
13};
14use bitflags::bitflags;
15#[cfg(feature = "no_std")]
16use hashbrown::hash_map::Entry;
17#[cfg(not(feature = "no_std"))]
18use std::collections::hash_map::Entry;
19#[cfg(feature = "no_std")]
20use std::prelude::v1::*;
21use std::{
22    any::{type_name, TypeId},
23    collections::BTreeMap,
24    fmt,
25    ops::{Add, AddAssign},
26};
27
28#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
29use crate::func::register::Mut;
30
31/// Initial capacity of the hashmap for functions.
32const FN_MAP_SIZE: usize = 16;
33
34/// A type representing the namespace of a function.
35#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
36#[cfg_attr(
37    feature = "metadata",
38    derive(serde::Serialize, serde::Deserialize),
39    serde(rename_all = "camelCase")
40)]
41#[non_exhaustive]
42pub enum FnNamespace {
43    /// Module namespace only.
44    ///
45    /// Ignored under `no_module`.
46    Internal,
47    /// Expose to global namespace.
48    Global,
49}
50
51impl FnNamespace {
52    /// Is this a module namespace?
53    #[inline(always)]
54    #[must_use]
55    pub const fn is_module_namespace(self) -> bool {
56        match self {
57            Self::Internal => true,
58            Self::Global => false,
59        }
60    }
61    /// Is this a global namespace?
62    #[inline(always)]
63    #[must_use]
64    pub const fn is_global_namespace(self) -> bool {
65        match self {
66            Self::Internal => false,
67            Self::Global => true,
68        }
69    }
70}
71
72/// A type containing the metadata of a single registered function.
73#[derive(Debug, Clone, Eq, PartialEq, Hash)]
74#[non_exhaustive]
75pub struct FuncMetadata {
76    /// Hash value.
77    pub hash: u64,
78    /// Function namespace.
79    pub namespace: FnNamespace,
80    /// Function access mode.
81    pub access: FnAccess,
82    /// Function name.
83    pub name: Identifier,
84    /// Number of parameters.
85    pub num_params: usize,
86    /// Parameter types (if applicable).
87    pub param_types: FnArgsVec<TypeId>,
88    /// Parameter names and types (if available).
89    #[cfg(feature = "metadata")]
90    pub params_info: FnArgsVec<Identifier>,
91    /// Return type name.
92    #[cfg(feature = "metadata")]
93    pub return_type: Identifier,
94    /// Comments.
95    #[cfg(feature = "metadata")]
96    pub comments: crate::StaticVec<SmartString>,
97}
98
99impl FuncMetadata {
100    /// _(metadata)_ Generate a signature of the function.
101    /// Exported under the `metadata` feature only.
102    #[cfg(feature = "metadata")]
103    #[must_use]
104    pub fn gen_signature<'a>(
105        &'a self,
106        type_mapper: impl Fn(&'a str) -> std::borrow::Cow<'a, str>,
107    ) -> String {
108        let mut signature = format!("{}(", self.name);
109
110        let return_type = format_param_type_for_display(&self.return_type, true);
111
112        if self.params_info.is_empty() {
113            for x in 0..self.num_params {
114                signature.push('_');
115                if x < self.num_params - 1 {
116                    signature.push_str(", ");
117                }
118            }
119        } else {
120            let params = self
121                .params_info
122                .iter()
123                .map(|param| {
124                    let mut segment = param.splitn(2, ':');
125                    let name = match segment.next().unwrap().trim() {
126                        "" => "_".into(),
127                        s => s,
128                    };
129                    let result: std::borrow::Cow<_> = segment.next().map_or_else(
130                        || name.into(),
131                        |typ| {
132                            format!(
133                                "{name}: {}",
134                                format_param_type_for_display(&type_mapper(typ), false)
135                            )
136                            .into()
137                        },
138                    );
139                    result
140                })
141                .collect::<crate::FnArgsVec<_>>();
142            signature.push_str(&params.join(", "));
143        }
144        signature.push(')');
145
146        if !return_type.is_empty() {
147            signature.push_str(" -> ");
148            signature.push_str(&return_type);
149        }
150
151        signature
152    }
153}
154
155/// _(internals)_ Calculate a [`u64`] hash key from a namespace-qualified function name and parameter types.
156/// Exported under the `internals` feature only.
157///
158/// Module names are passed in via `&str` references from an iterator.
159/// Parameter types are passed in via [`TypeId`] values from an iterator.
160///
161/// # Note
162///
163/// The first module name is skipped.  Hashing starts from the _second_ module in the chain.
164#[inline]
165pub fn calc_native_fn_hash<'a>(
166    modules: impl IntoIterator<Item = &'a str, IntoIter = impl ExactSizeIterator<Item = &'a str>>,
167    fn_name: &str,
168    params: &[TypeId],
169) -> u64 {
170    calc_fn_hash_full(
171        calc_fn_hash(modules, fn_name, params.len()),
172        params.iter().copied(),
173    )
174}
175
176/// Type for fine-tuned module function registration.
177#[derive(Debug, Clone, Eq, PartialEq, Hash)]
178pub struct FuncRegistration {
179    /// Function metadata.
180    metadata: FuncMetadata,
181    /// Is the function pure?
182    purity: Option<bool>,
183    /// Is the function volatile?
184    volatility: Option<bool>,
185}
186
187impl FuncRegistration {
188    /// Create a new [`FuncRegistration`].
189    ///
190    /// # Defaults
191    ///
192    /// * **Accessibility**: The function namespace is [`FnNamespace::Internal`].
193    ///
194    /// * **Purity**: The function is assumed to be _pure_ unless it is a property setter or an index setter.
195    ///
196    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
197    ///
198    /// * **Metadata**: No metadata for the function is registered.
199    ///
200    /// ```
201    /// # use rhai::{Module, FuncRegistration, FnNamespace};
202    /// let mut module = Module::new();
203    ///
204    /// fn inc(x: i64) -> i64 { x + 1 }
205    ///
206    /// let f = FuncRegistration::new("inc")
207    ///     .with_namespace(FnNamespace::Global)
208    ///     .set_into_module(&mut module, inc);
209    ///
210    /// let hash = f.hash;
211    ///
212    /// assert!(module.contains_fn(hash));
213    /// ```
214    pub fn new(name: impl Into<Identifier>) -> Self {
215        Self {
216            metadata: FuncMetadata {
217                hash: 0,
218                name: name.into(),
219                namespace: FnNamespace::Internal,
220                access: FnAccess::Public,
221                num_params: 0,
222                param_types: <_>::default(),
223                #[cfg(feature = "metadata")]
224                params_info: <_>::default(),
225                #[cfg(feature = "metadata")]
226                return_type: "".into(),
227                #[cfg(feature = "metadata")]
228                comments: <_>::default(),
229            },
230            purity: None,
231            volatility: None,
232        }
233    }
234    /// Create a new [`FuncRegistration`] for a property getter.
235    ///
236    /// Not available under `no_object`.
237    ///
238    /// # Defaults
239    ///
240    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
241    ///
242    /// * **Purity**: The function is assumed to be _pure_.
243    ///
244    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
245    ///
246    /// * **Metadata**: No metadata for the function is registered.
247    #[cfg(not(feature = "no_object"))]
248    #[inline(always)]
249    pub fn new_getter(prop: impl AsRef<str>) -> Self {
250        Self::new(crate::engine::make_getter(prop.as_ref())).with_namespace(FnNamespace::Global)
251    }
252    /// Create a new [`FuncRegistration`] for a property setter.
253    ///
254    /// Not available under `no_object`.
255    ///
256    /// # Defaults
257    ///
258    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
259    ///
260    /// * **Purity**: The function is assumed to be _no-pure_.
261    ///
262    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
263    ///
264    /// * **Metadata**: No metadata for the function is registered.
265    #[cfg(not(feature = "no_object"))]
266    #[inline(always)]
267    pub fn new_setter(prop: impl AsRef<str>) -> Self {
268        Self::new(crate::engine::make_setter(prop.as_ref()))
269            .with_namespace(FnNamespace::Global)
270            .with_purity(false)
271    }
272    /// Create a new [`FuncRegistration`] for an index getter.
273    ///
274    /// Not available under both `no_index` and `no_object`.
275    ///
276    /// # Defaults
277    ///
278    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
279    ///
280    /// * **Purity**: The function is assumed to be _pure_.
281    ///
282    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
283    ///
284    /// * **Metadata**: No metadata for the function is registered.
285    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
286    #[inline(always)]
287    pub fn new_index_getter() -> Self {
288        Self::new(crate::engine::FN_IDX_GET).with_namespace(FnNamespace::Global)
289    }
290    /// Create a new [`FuncRegistration`] for an index setter.
291    ///
292    /// Not available under both `no_index` and `no_object`.
293    ///
294    /// # Defaults
295    ///
296    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
297    ///
298    /// * **Purity**: The function is assumed to be _no-pure_.
299    ///
300    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
301    ///
302    /// * **Metadata**: No metadata for the function is registered.
303    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
304    #[inline(always)]
305    pub fn new_index_setter() -> Self {
306        Self::new(crate::engine::FN_IDX_SET)
307            .with_namespace(FnNamespace::Global)
308            .with_purity(false)
309    }
310    /// Set the [namespace][`FnNamespace`] of the function.
311    pub fn with_namespace(mut self, namespace: FnNamespace) -> Self {
312        self.metadata.namespace = namespace;
313        self
314    }
315    /// Set whether the function is _pure_.
316    /// A pure function has no side effects.
317    pub fn with_purity(mut self, pure: bool) -> Self {
318        self.purity = Some(pure);
319        self
320    }
321    /// Set whether the function is _volatile_.
322    /// A volatile function does not guarantee the same result for the same input(s).
323    pub fn with_volatility(mut self, volatile: bool) -> Self {
324        self.volatility = Some(volatile);
325        self
326    }
327    /// _(metadata)_ Set the function's parameter names and/or types.
328    /// Exported under the `metadata` feature only.
329    ///
330    /// The input is a list of strings, each of which is either a parameter name or a parameter name/type pair.
331    ///
332    /// The _last_ string should be the _type_ of the return value.
333    ///
334    /// # Parameter Examples
335    ///
336    /// `"foo: &str"`   <- parameter name = `foo`, type = `&str`  
337    /// `"bar"`         <- parameter name = `bar`, type unknown  
338    /// `"_: i64"`      <- parameter name unknown, type = `i64`  
339    /// `"MyType"`      <- parameter name unknown, type = `MyType`  
340    #[cfg(feature = "metadata")]
341    pub fn with_params_info<S: AsRef<str>>(mut self, params: impl IntoIterator<Item = S>) -> Self {
342        self.metadata.params_info = params.into_iter().map(|s| s.as_ref().into()).collect();
343        self
344    }
345    /// _(metadata)_ Set the function's doc-comments.
346    /// Exported under the `metadata` feature only.
347    ///
348    /// The input is a list of strings, each of which is either a block of single-line doc-comments
349    /// or a single block doc-comment.
350    ///
351    /// ## Comments
352    ///
353    /// Single-line doc-comments typically start with `///` and should be merged, with line-breaks,
354    /// into a single string without a final termination line-break.
355    ///
356    /// Block doc-comments typically start with `/**` and end with `*/` and should be kept in a
357    /// separate string.
358    ///
359    /// Leading white-spaces should be stripped, and each string should always start with the
360    /// corresponding doc-comment leader: `///` or `/**`.
361    ///
362    /// Each line in non-block doc-comments should start with `///`.
363    #[cfg(feature = "metadata")]
364    pub fn with_comments<S: AsRef<str>>(mut self, comments: impl IntoIterator<Item = S>) -> Self {
365        self.metadata.comments = comments.into_iter().map(|s| s.as_ref().into()).collect();
366        self
367    }
368    /// Register the function into the specified [`Engine`].
369    #[inline]
370    pub fn register_into_engine<A: 'static, const N: usize, const X: bool, R, const F: bool, FUNC>(
371        self,
372        engine: &mut Engine,
373        func: FUNC,
374    ) -> &FuncMetadata
375    where
376        R: Variant + Clone,
377        FUNC: RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
378    {
379        self.with_namespace(FnNamespace::Global)
380            .set_into_module(engine.global_namespace_mut(), func)
381    }
382    /// Register the function into the specified [`Module`].
383    #[inline]
384    pub fn set_into_module<A: 'static, const N: usize, const X: bool, R, const F: bool, FUNC>(
385        self,
386        module: &mut Module,
387        func: FUNC,
388    ) -> &FuncMetadata
389    where
390        R: Variant + Clone,
391        FUNC: RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
392    {
393        let is_pure = self.purity.unwrap_or_else(|| {
394            // default to pure unless specified
395            let is_pure = true;
396
397            #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
398            let is_pure = is_pure
399                && (FUNC::num_params() != 3 || self.metadata.name != crate::engine::FN_IDX_SET);
400
401            #[cfg(not(feature = "no_object"))]
402            let is_pure = is_pure
403                && (FUNC::num_params() != 2
404                    || !self.metadata.name.starts_with(crate::engine::FN_SET));
405            is_pure
406        });
407        let is_volatile = self.volatility.unwrap_or(false);
408
409        let func = func.into_rhai_function(is_pure, is_volatile);
410
411        // Clear flags
412        let mut reg = self;
413        reg.purity = None;
414        reg.volatility = None;
415
416        reg.set_into_module_raw(module, FUNC::param_types(), func)
417    }
418    /// Register the function into the specified [`Module`].
419    ///
420    /// # WARNING - Low Level API
421    ///
422    /// This function is very low level.  It takes a list of [`TypeId`][std::any::TypeId]'s
423    /// indicating the actual types of the parameters.
424    ///
425    /// # Panics
426    ///
427    /// Panics if the type of the first parameter is [`Array`][crate::Array], [`Map`][crate::Map],
428    /// [`String`], [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT] and
429    /// the function name indicates that it is an index getter or setter.
430    ///
431    /// Indexers for arrays, object maps, strings and integers cannot be registered.
432    #[inline]
433    pub fn set_into_module_raw(
434        self,
435        module: &mut Module,
436        arg_types: impl AsRef<[TypeId]>,
437        func: RhaiFunc,
438    ) -> &FuncMetadata {
439        // Make sure that conflicting flags should not be set.
440        debug_assert!(self.purity.is_none());
441        debug_assert!(self.volatility.is_none());
442
443        let mut f = self.metadata;
444
445        f.num_params = arg_types.as_ref().len();
446        f.param_types.extend(arg_types.as_ref().iter().copied());
447
448        #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
449        if (f.name == crate::engine::FN_IDX_GET && f.num_params == 2)
450            || (f.name == crate::engine::FN_IDX_SET && f.num_params == 3)
451        {
452            if let Some(&type_id) = f.param_types.first() {
453                #[cfg(not(feature = "no_index"))]
454                assert!(
455                    type_id != TypeId::of::<crate::Array>(),
456                    "Cannot register indexer for arrays."
457                );
458
459                #[cfg(not(feature = "no_object"))]
460                assert!(
461                    type_id != TypeId::of::<crate::Map>(),
462                    "Cannot register indexer for object maps."
463                );
464
465                assert!(
466                    type_id != TypeId::of::<String>()
467                        && type_id != TypeId::of::<&str>()
468                        && type_id != TypeId::of::<crate::ImmutableString>(),
469                    "Cannot register indexer for strings."
470                );
471
472                assert!(
473                    type_id != TypeId::of::<crate::INT>(),
474                    "Cannot register indexer for integers."
475                );
476            }
477        }
478
479        let is_method = func.is_method();
480
481        f.param_types
482            .iter_mut()
483            .enumerate()
484            .for_each(|(i, type_id)| *type_id = Module::map_type(!is_method || i > 0, *type_id));
485
486        let is_dynamic = f
487            .param_types
488            .iter()
489            .any(|&type_id| type_id == TypeId::of::<Dynamic>());
490
491        #[cfg(feature = "metadata")]
492        if f.params_info.len() > f.param_types.len() {
493            f.return_type = f.params_info.pop().unwrap();
494        }
495
496        let hash_base = calc_fn_hash(None, &f.name, f.param_types.len());
497        let hash_fn = calc_fn_hash_full(hash_base, f.param_types.iter().copied());
498        f.hash = hash_fn;
499
500        // Catch hash collisions in testing environment only.
501        #[cfg(feature = "testing-environ")]
502        if let Some(fx) = module.functions.as_ref().and_then(|f| f.get(&hash_base)) {
503            unreachable!(
504                "Hash {} already exists when registering function {}:\n{:#?}",
505                hash_base, f.name, fx
506            );
507        }
508
509        if is_dynamic {
510            module.dynamic_functions_filter.mark(hash_base);
511        }
512
513        module
514            .flags
515            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
516
517        let entry = match module
518            .functions
519            .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE))
520            .entry(hash_fn)
521        {
522            Entry::Occupied(mut entry) => {
523                entry.insert((func, f.into()));
524                entry.into_mut()
525            }
526            Entry::Vacant(entry) => entry.insert((func, f.into())),
527        };
528
529        &*entry.1
530    }
531}
532
533bitflags! {
534    /// Bit-flags containing all status for [`Module`].
535    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
536    pub struct ModuleFlags: u8 {
537        /// Is the [`Module`] internal?
538        const INTERNAL = 0b0000_0001;
539        /// Is the [`Module`] part of a standard library?
540        const STANDARD_LIB = 0b0000_0010;
541        /// Is the [`Module`] indexed?
542        const INDEXED = 0b0000_0100;
543        /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
544        const INDEXED_GLOBAL_FUNCTIONS = 0b0000_1000;
545    }
546}
547
548/// A module which may contain variables, sub-modules, external Rust functions,
549/// and/or script-defined functions.
550#[derive(Clone)]
551pub struct Module {
552    /// ID identifying the module.
553    id: Option<ImmutableString>,
554    /// Module documentation.
555    #[cfg(feature = "metadata")]
556    doc: SmartString,
557    /// Custom types.
558    custom_types: CustomTypesCollection,
559    /// Sub-modules.
560    modules: BTreeMap<Identifier, SharedModule>,
561    /// [`Module`] variables.
562    variables: BTreeMap<Identifier, Dynamic>,
563    /// Flattened collection of all [`Module`] variables, including those in sub-modules.
564    all_variables: Option<StraightHashMap<Dynamic>>,
565    /// Functions (both native Rust and scripted).
566    functions: Option<StraightHashMap<(RhaiFunc, Box<FuncMetadata>)>>,
567    /// Flattened collection of all functions, native Rust and scripted.
568    /// including those in sub-modules.
569    all_functions: Option<StraightHashMap<RhaiFunc>>,
570    /// Bloom filter on native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters.
571    dynamic_functions_filter: BloomFilterU64,
572    /// Iterator functions, keyed by the type producing the iterator.
573    type_iterators: BTreeMap<TypeId, Shared<FnIterator>>,
574    /// Flattened collection of iterator functions, including those in sub-modules.
575    all_type_iterators: BTreeMap<TypeId, Shared<FnIterator>>,
576    /// Flags.
577    pub(crate) flags: ModuleFlags,
578}
579
580impl Default for Module {
581    #[inline(always)]
582    #[must_use]
583    fn default() -> Self {
584        Self::new()
585    }
586}
587
588impl fmt::Debug for Module {
589    #[cold]
590    #[inline(never)]
591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592        let mut d = f.debug_struct("Module");
593
594        d.field("id", &self.id)
595            .field(
596                "custom_types",
597                &self.custom_types.iter().map(|(k, _)| k).collect::<Vec<_>>(),
598            )
599            .field(
600                "modules",
601                &self
602                    .modules
603                    .keys()
604                    .map(SmartString::as_str)
605                    .collect::<Vec<_>>(),
606            )
607            .field("vars", &self.variables)
608            .field(
609                "functions",
610                &self
611                    .iter_fn()
612                    .map(|(_f, _m)| {
613                        #[cfg(not(feature = "metadata"))]
614                        return _f.to_string();
615                        #[cfg(feature = "metadata")]
616                        return _m.gen_signature(|s| s.into());
617                    })
618                    .collect::<Vec<_>>(),
619            )
620            .field("flags", &self.flags);
621
622        #[cfg(feature = "metadata")]
623        d.field("doc", &self.doc);
624
625        d.finish()
626    }
627}
628
629#[cfg(not(feature = "no_function"))]
630impl<T: IntoIterator<Item = Shared<crate::ast::ScriptFuncDef>>> From<T> for Module {
631    fn from(iter: T) -> Self {
632        let mut module = Self::new();
633        iter.into_iter().for_each(|fn_def| {
634            module.set_script_fn(fn_def);
635        });
636        module
637    }
638}
639
640impl<M: AsRef<Module>> Add<M> for &Module {
641    type Output = Module;
642
643    #[inline]
644    fn add(self, rhs: M) -> Self::Output {
645        let mut module = self.clone();
646        module.merge(rhs.as_ref());
647        module
648    }
649}
650
651impl<M: AsRef<Self>> Add<M> for Module {
652    type Output = Self;
653
654    #[inline(always)]
655    fn add(mut self, rhs: M) -> Self::Output {
656        self.merge(rhs.as_ref());
657        self
658    }
659}
660
661impl<M: Into<Self>> AddAssign<M> for Module {
662    #[inline(always)]
663    fn add_assign(&mut self, rhs: M) {
664        self.combine(rhs.into());
665    }
666}
667
668#[inline(always)]
669fn new_hash_map<T>(size: usize) -> StraightHashMap<T> {
670    StraightHashMap::with_capacity_and_hasher(size, <_>::default())
671}
672
673impl Module {
674    /// Create a new [`Module`].
675    ///
676    /// # Example
677    ///
678    /// ```
679    /// # use rhai::Module;
680    /// let mut module = Module::new();
681    /// module.set_var("answer", 42_i64);
682    /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
683    /// ```
684    #[inline(always)]
685    #[must_use]
686    pub const fn new() -> Self {
687        Self {
688            id: None,
689            #[cfg(feature = "metadata")]
690            doc: SmartString::new_const(),
691            custom_types: CustomTypesCollection::new(),
692            modules: BTreeMap::new(),
693            variables: BTreeMap::new(),
694            all_variables: None,
695            functions: None,
696            all_functions: None,
697            dynamic_functions_filter: BloomFilterU64::new(),
698            type_iterators: BTreeMap::new(),
699            all_type_iterators: BTreeMap::new(),
700            flags: ModuleFlags::INDEXED,
701        }
702    }
703
704    /// Get the ID of the [`Module`], if any.
705    ///
706    /// # Example
707    ///
708    /// ```
709    /// # use rhai::Module;
710    /// let mut module = Module::new();
711    /// module.set_id("hello");
712    /// assert_eq!(module.id(), Some("hello"));
713    /// ```
714    #[inline]
715    #[must_use]
716    pub fn id(&self) -> Option<&str> {
717        self.id.as_deref()
718    }
719
720    /// Get the ID of the [`Module`] as an [`Identifier`], if any.
721    #[inline(always)]
722    #[must_use]
723    pub(crate) const fn id_raw(&self) -> Option<&ImmutableString> {
724        self.id.as_ref()
725    }
726
727    /// Set the ID of the [`Module`].
728    ///
729    /// If the string is empty, it is equivalent to clearing the ID.
730    ///
731    /// # Example
732    ///
733    /// ```
734    /// # use rhai::Module;
735    /// let mut module = Module::new();
736    /// module.set_id("hello");
737    /// assert_eq!(module.id(), Some("hello"));
738    /// ```
739    #[inline(always)]
740    pub fn set_id(&mut self, id: impl Into<ImmutableString>) -> &mut Self {
741        let id = id.into();
742        self.id = (!id.is_empty()).then_some(id);
743        self
744    }
745
746    /// Clear the ID of the [`Module`].
747    ///
748    /// # Example
749    ///
750    /// ```
751    /// # use rhai::Module;
752    /// let mut module = Module::new();
753    /// module.set_id("hello");
754    /// assert_eq!(module.id(), Some("hello"));
755    /// module.clear_id();
756    /// assert_eq!(module.id(), None);
757    /// ```
758    #[inline(always)]
759    pub fn clear_id(&mut self) -> &mut Self {
760        self.id = None;
761        self
762    }
763
764    /// Get the documentation of the [`Module`], if any.
765    /// Exported under the `metadata` feature only.
766    ///
767    /// # Example
768    ///
769    /// ```
770    /// # use rhai::Module;
771    /// let mut module = Module::new();
772    /// module.set_doc("//! This is my special module.");
773    /// assert_eq!(module.doc(), "//! This is my special module.");
774    /// ```
775    #[cfg(feature = "metadata")]
776    #[inline(always)]
777    #[must_use]
778    pub fn doc(&self) -> &str {
779        &self.doc
780    }
781
782    /// Set the documentation of the [`Module`].
783    /// Exported under the `metadata` feature only.
784    ///
785    /// If the string is empty, it is equivalent to clearing the documentation.
786    ///
787    /// # Example
788    ///
789    /// ```
790    /// # use rhai::Module;
791    /// let mut module = Module::new();
792    /// module.set_doc("//! This is my special module.");
793    /// assert_eq!(module.doc(), "//! This is my special module.");
794    /// ```
795    #[cfg(feature = "metadata")]
796    #[inline(always)]
797    pub fn set_doc(&mut self, doc: impl Into<crate::SmartString>) -> &mut Self {
798        self.doc = doc.into();
799        self
800    }
801
802    /// Clear the documentation of the [`Module`].
803    ///
804    /// # Example
805    ///
806    /// ```
807    /// # use rhai::Module;
808    /// let mut module = Module::new();
809    /// module.set_doc("//! This is my special module.");
810    /// assert_eq!(module.doc(), "//! This is my special module.");
811    /// module.clear_doc();
812    /// assert_eq!(module.doc(), "");
813    /// ```
814    #[cfg(feature = "metadata")]
815    #[inline(always)]
816    pub fn clear_doc(&mut self) -> &mut Self {
817        self.doc.clear();
818        self
819    }
820
821    /// Clear the [`Module`].
822    #[inline(always)]
823    pub fn clear(&mut self) {
824        #[cfg(feature = "metadata")]
825        self.doc.clear();
826        self.custom_types.clear();
827        self.modules.clear();
828        self.variables.clear();
829        self.all_variables = None;
830        self.functions = None;
831        self.all_functions = None;
832        self.dynamic_functions_filter.clear();
833        self.type_iterators.clear();
834        self.all_type_iterators.clear();
835        self.flags
836            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
837    }
838
839    /// Map a custom type to a friendly display name.
840    ///
841    /// # Example
842    ///
843    /// ```
844    /// # use rhai::Module;
845    /// #[derive(Clone)]
846    /// struct TestStruct;
847    ///
848    /// let name = std::any::type_name::<TestStruct>();
849    ///
850    /// let mut module = Module::new();
851    ///
852    /// module.set_custom_type::<TestStruct>("MyType");
853    ///
854    /// assert_eq!(module.get_custom_type_display_by_name(name), Some("MyType"));
855    /// ```
856    #[inline(always)]
857    pub fn set_custom_type<T>(&mut self, name: &str) -> &mut Self {
858        self.custom_types.add_type::<T>(name);
859        self
860    }
861    /// Map a custom type to a friendly display name.
862    /// Exported under the `metadata` feature only.
863    ///
864    /// ## Comments
865    ///
866    /// Block doc-comments should be kept in a separate string slice.
867    ///
868    /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break.
869    ///
870    /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
871    /// doc-comment leader: `///` or `/**`.
872    ///
873    /// Each line in non-block doc-comments should start with `///`.
874    #[cfg(feature = "metadata")]
875    #[inline(always)]
876    pub fn set_custom_type_with_comments<T>(&mut self, name: &str, comments: &[&str]) -> &mut Self {
877        self.custom_types
878            .add_type_with_comments::<T>(name, comments);
879        self
880    }
881    /// Map a custom type to a friendly display name.
882    ///
883    /// ```
884    /// # use rhai::Module;
885    /// #[derive(Clone)]
886    /// struct TestStruct;
887    ///
888    /// let name = std::any::type_name::<TestStruct>();
889    ///
890    /// let mut module = Module::new();
891    ///
892    /// module.set_custom_type_raw(name, "MyType");
893    ///
894    /// assert_eq!(module.get_custom_type_display_by_name(name), Some("MyType"));
895    /// ```
896    #[inline(always)]
897    pub fn set_custom_type_raw(
898        &mut self,
899        type_name: impl Into<Identifier>,
900        display_name: impl Into<Identifier>,
901    ) -> &mut Self {
902        self.custom_types.add(type_name, display_name);
903        self
904    }
905    /// Map a custom type to a friendly display name.
906    /// Exported under the `metadata` feature only.
907    ///
908    /// ## Comments
909    ///
910    /// Block doc-comments should be kept in a separate string slice.
911    ///
912    /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break.
913    ///
914    /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
915    /// doc-comment leader: `///` or `/**`.
916    ///
917    /// Each line in non-block doc-comments should start with `///`.
918    #[cfg(feature = "metadata")]
919    #[inline(always)]
920    pub fn set_custom_type_with_comments_raw<C: Into<SmartString>>(
921        &mut self,
922        type_name: impl Into<Identifier>,
923        display_name: impl Into<Identifier>,
924        comments: impl IntoIterator<Item = C>,
925    ) -> &mut Self {
926        self.custom_types
927            .add_with_comments(type_name, display_name, comments);
928        self
929    }
930    /// Get the display name of a registered custom type.
931    ///
932    /// # Example
933    ///
934    /// ```
935    /// # use rhai::Module;
936    /// #[derive(Clone)]
937    /// struct TestStruct;
938    ///
939    /// let name = std::any::type_name::<TestStruct>();
940    ///
941    /// let mut module = Module::new();
942    ///
943    /// module.set_custom_type::<TestStruct>("MyType");
944    ///
945    /// assert_eq!(module.get_custom_type_display_by_name(name), Some("MyType"));
946    /// ```
947    #[inline]
948    #[must_use]
949    pub fn get_custom_type_display_by_name(&self, type_name: &str) -> Option<&str> {
950        self.get_custom_type_by_name_raw(type_name)
951            .map(|typ| typ.display_name.as_str())
952    }
953    /// Get the display name of a registered custom type.
954    ///
955    /// # Example
956    ///
957    /// ```
958    /// # use rhai::Module;
959    /// #[derive(Clone)]
960    /// struct TestStruct;
961    ///
962    /// let name = std::any::type_name::<TestStruct>();
963    ///
964    /// let mut module = Module::new();
965    ///
966    /// module.set_custom_type::<TestStruct>("MyType");
967    ///
968    /// assert_eq!(module.get_custom_type_display::<TestStruct>(), Some("MyType"));
969    /// ```
970    #[inline(always)]
971    #[must_use]
972    pub fn get_custom_type_display<T>(&self) -> Option<&str> {
973        self.get_custom_type_display_by_name(type_name::<T>())
974    }
975    /// _(internals)_ Get a registered custom type .
976    /// Exported under the `internals` feature only.
977    #[cfg(feature = "internals")]
978    #[inline(always)]
979    #[must_use]
980    pub fn get_custom_type_raw<T>(&self) -> Option<&CustomTypeInfo> {
981        self.get_custom_type_by_name_raw(type_name::<T>())
982    }
983    /// Get a registered custom type .
984    #[cfg(not(feature = "internals"))]
985    #[inline(always)]
986    #[must_use]
987    pub fn get_custom_type_raw<T>(&self) -> Option<&CustomTypeInfo> {
988        self.get_custom_type_by_name_raw(type_name::<T>())
989    }
990    /// _(internals)_ Get a registered custom type by its type name.
991    /// Exported under the `internals` feature only.
992    #[cfg(feature = "internals")]
993    #[inline(always)]
994    #[must_use]
995    pub fn get_custom_type_by_name_raw(&self, type_name: &str) -> Option<&CustomTypeInfo> {
996        self.custom_types.get(type_name)
997    }
998    /// Get a registered custom type by its type name.
999    #[cfg(not(feature = "internals"))]
1000    #[inline(always)]
1001    #[must_use]
1002    fn get_custom_type_by_name_raw(&self, type_name: &str) -> Option<&CustomTypeInfo> {
1003        self.custom_types.get(type_name)
1004    }
1005
1006    /// Returns `true` if this [`Module`] contains no items.
1007    ///
1008    /// # Example
1009    ///
1010    /// ```
1011    /// # use rhai::Module;
1012    /// let module = Module::new();
1013    /// assert!(module.is_empty());
1014    /// ```
1015    #[inline]
1016    #[must_use]
1017    pub fn is_empty(&self) -> bool {
1018        !self.flags.intersects(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS)
1019            && self
1020                .functions
1021                .as_ref()
1022                .map_or(true, StraightHashMap::is_empty)
1023            && self.variables.is_empty()
1024            && self.modules.is_empty()
1025            && self.type_iterators.is_empty()
1026            && self
1027                .all_functions
1028                .as_ref()
1029                .map_or(true, StraightHashMap::is_empty)
1030            && self
1031                .all_variables
1032                .as_ref()
1033                .map_or(true, StraightHashMap::is_empty)
1034            && self.all_type_iterators.is_empty()
1035    }
1036
1037    /// Is the [`Module`] indexed?
1038    ///
1039    /// A module must be indexed before it can be used in an `import` statement.
1040    ///
1041    /// # Example
1042    ///
1043    /// ```
1044    /// # use rhai::Module;
1045    /// let mut module = Module::new();
1046    /// assert!(module.is_indexed());
1047    ///
1048    /// module.set_native_fn("foo", |x: &mut i64, y: i64| { *x = y; Ok(()) });
1049    /// assert!(!module.is_indexed());
1050    ///
1051    /// # #[cfg(not(feature = "no_module"))]
1052    /// # {
1053    /// module.build_index();
1054    /// assert!(module.is_indexed());
1055    /// # }
1056    /// ```
1057    #[inline(always)]
1058    #[must_use]
1059    pub const fn is_indexed(&self) -> bool {
1060        self.flags.intersects(ModuleFlags::INDEXED)
1061    }
1062
1063    /// _(metadata)_ Generate signatures for all the non-private functions in the [`Module`].
1064    /// Exported under the `metadata` feature only.
1065    #[cfg(feature = "metadata")]
1066    #[inline]
1067    pub fn gen_fn_signatures_with_mapper<'a>(
1068        &'a self,
1069        type_mapper: impl Fn(&'a str) -> std::borrow::Cow<'a, str> + 'a,
1070    ) -> impl Iterator<Item = String> + 'a {
1071        self.iter_fn()
1072            .map(|(_, m)| m)
1073            .filter(|&f| match f.access {
1074                FnAccess::Public => true,
1075                FnAccess::Private => false,
1076            })
1077            .map(move |m| m.gen_signature(&type_mapper))
1078    }
1079
1080    /// Does a variable exist in the [`Module`]?
1081    ///
1082    /// # Example
1083    ///
1084    /// ```
1085    /// # use rhai::Module;
1086    /// let mut module = Module::new();
1087    /// module.set_var("answer", 42_i64);
1088    /// assert!(module.contains_var("answer"));
1089    /// ```
1090    #[inline(always)]
1091    #[must_use]
1092    pub fn contains_var(&self, name: &str) -> bool {
1093        self.variables.contains_key(name)
1094    }
1095
1096    /// Get the value of a [`Module`] variable.
1097    ///
1098    /// # Example
1099    ///
1100    /// ```
1101    /// # use rhai::Module;
1102    /// let mut module = Module::new();
1103    /// module.set_var("answer", 42_i64);
1104    /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
1105    /// ```
1106    #[inline]
1107    #[must_use]
1108    pub fn get_var_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
1109        self.get_var(name).and_then(Dynamic::try_cast::<T>)
1110    }
1111
1112    /// Get a [`Module`] variable as a [`Dynamic`].
1113    ///
1114    /// # Example
1115    ///
1116    /// ```
1117    /// # use rhai::Module;
1118    /// let mut module = Module::new();
1119    /// module.set_var("answer", 42_i64);
1120    /// assert_eq!(module.get_var("answer").expect("answer should exist").cast::<i64>(), 42);
1121    /// ```
1122    #[inline(always)]
1123    #[must_use]
1124    pub fn get_var(&self, name: &str) -> Option<Dynamic> {
1125        self.variables.get(name).cloned()
1126    }
1127
1128    /// Set a variable into the [`Module`].
1129    ///
1130    /// If there is an existing variable of the same name, it is replaced.
1131    ///
1132    /// # Example
1133    ///
1134    /// ```
1135    /// # use rhai::Module;
1136    /// let mut module = Module::new();
1137    /// module.set_var("answer", 42_i64);
1138    /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
1139    /// ```
1140    #[inline]
1141    pub fn set_var(
1142        &mut self,
1143        name: impl Into<Identifier>,
1144        value: impl Variant + Clone,
1145    ) -> &mut Self {
1146        let ident = name.into();
1147        let value = Dynamic::from(value);
1148
1149        if self.is_indexed() {
1150            let hash_var = crate::calc_var_hash(Some(""), &ident);
1151
1152            // Catch hash collisions in testing environment only.
1153            #[cfg(feature = "testing-environ")]
1154            assert!(
1155                self.all_variables
1156                    .as_ref()
1157                    .map_or(true, |map| !map.contains_key(&hash_var)),
1158                "Hash {} already exists when registering variable {}",
1159                hash_var,
1160                ident
1161            );
1162
1163            self.all_variables
1164                .get_or_insert_with(Default::default)
1165                .insert(hash_var, value.clone());
1166        }
1167        self.variables.insert(ident, value);
1168        self
1169    }
1170
1171    /// Get a namespace-qualified [`Module`] variable as a [`Dynamic`].
1172    #[cfg(not(feature = "no_module"))]
1173    #[inline]
1174    pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option<Dynamic> {
1175        self.all_variables
1176            .as_ref()
1177            .and_then(|c| c.get(&hash_var).cloned())
1178    }
1179
1180    /// Set a script-defined function into the [`Module`].
1181    ///
1182    /// If there is an existing function of the same name and number of arguments, it is replaced.
1183    #[cfg(not(feature = "no_function"))]
1184    #[inline]
1185    pub fn set_script_fn(&mut self, fn_def: impl Into<Shared<crate::ast::ScriptFuncDef>>) -> u64 {
1186        let fn_def = fn_def.into();
1187
1188        // None + function name + number of arguments.
1189        let namespace = FnNamespace::Internal;
1190        let num_params = fn_def.params.len();
1191        let hash_script = crate::calc_fn_hash(None, &fn_def.name, num_params);
1192        #[cfg(not(feature = "no_object"))]
1193        let (hash_script, namespace) =
1194            fn_def
1195                .this_type
1196                .as_ref()
1197                .map_or((hash_script, namespace), |this_type| {
1198                    (
1199                        crate::calc_typed_method_hash(hash_script, this_type),
1200                        FnNamespace::Global,
1201                    )
1202                });
1203
1204        // Catch hash collisions in testing environment only.
1205        #[cfg(feature = "testing-environ")]
1206        if let Some(f) = self.functions.as_ref().and_then(|f| f.get(&hash_script)) {
1207            unreachable!(
1208                "Hash {} already exists when registering function {:#?}:\n{:#?}",
1209                hash_script, fn_def, f
1210            );
1211        }
1212
1213        let metadata = FuncMetadata {
1214            hash: hash_script,
1215            name: fn_def.name.as_str().into(),
1216            namespace,
1217            access: fn_def.access,
1218            num_params,
1219            param_types: FnArgsVec::new_const(),
1220            #[cfg(feature = "metadata")]
1221            params_info: fn_def.params.iter().map(Into::into).collect(),
1222            #[cfg(feature = "metadata")]
1223            return_type: <_>::default(),
1224            #[cfg(feature = "metadata")]
1225            comments: crate::StaticVec::new_const(),
1226        };
1227
1228        self.functions
1229            .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE))
1230            .insert(hash_script, (fn_def.into(), metadata.into()));
1231
1232        self.flags
1233            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1234
1235        hash_script
1236    }
1237
1238    /// Get a shared reference to the script-defined function in the [`Module`] based on name
1239    /// and number of parameters.
1240    #[cfg(not(feature = "no_function"))]
1241    #[inline]
1242    #[must_use]
1243    pub fn get_script_fn(
1244        &self,
1245        name: impl AsRef<str>,
1246        num_params: usize,
1247    ) -> Option<&Shared<crate::ast::ScriptFuncDef>> {
1248        self.functions.as_ref().and_then(|lib| {
1249            let name = name.as_ref();
1250
1251            lib.values()
1252                .find(|(_, f)| f.num_params == num_params && f.name == name)
1253                .and_then(|(f, _)| f.get_script_fn_def())
1254        })
1255    }
1256
1257    /// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules,
1258    /// creating one if empty.
1259    ///
1260    /// # WARNING
1261    ///
1262    /// By taking a mutable reference, it is assumed that some sub-modules will be modified.
1263    /// Thus the [`Module`] is automatically set to be non-indexed.
1264    #[cfg(not(feature = "no_module"))]
1265    #[inline]
1266    #[must_use]
1267    pub(crate) fn get_sub_modules_mut(&mut self) -> &mut BTreeMap<Identifier, SharedModule> {
1268        // We must assume that the user has changed the sub-modules
1269        // (otherwise why take a mutable reference?)
1270        self.all_functions = None;
1271        self.all_variables = None;
1272        self.all_type_iterators.clear();
1273        self.flags
1274            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1275
1276        &mut self.modules
1277    }
1278
1279    /// Does a sub-module exist in the [`Module`]?
1280    ///
1281    /// # Example
1282    ///
1283    /// ```
1284    /// # use rhai::Module;
1285    /// let mut module = Module::new();
1286    /// let sub_module = Module::new();
1287    /// module.set_sub_module("question", sub_module);
1288    /// assert!(module.contains_sub_module("question"));
1289    /// ```
1290    #[inline(always)]
1291    #[must_use]
1292    pub fn contains_sub_module(&self, name: &str) -> bool {
1293        self.modules.contains_key(name)
1294    }
1295
1296    /// Get a sub-module in the [`Module`].
1297    ///
1298    /// # Example
1299    ///
1300    /// ```
1301    /// # use rhai::Module;
1302    /// let mut module = Module::new();
1303    /// let sub_module = Module::new();
1304    /// module.set_sub_module("question", sub_module);
1305    /// assert!(module.get_sub_module("question").is_some());
1306    /// ```
1307    #[inline]
1308    #[must_use]
1309    pub fn get_sub_module(&self, name: &str) -> Option<&Self> {
1310        self.modules.get(name).map(|m| &**m)
1311    }
1312
1313    /// Set a sub-module into the [`Module`].
1314    ///
1315    /// If there is an existing sub-module of the same name, it is replaced.
1316    ///
1317    /// # Example
1318    ///
1319    /// ```
1320    /// # use rhai::Module;
1321    /// let mut module = Module::new();
1322    /// let sub_module = Module::new();
1323    /// module.set_sub_module("question", sub_module);
1324    /// assert!(module.get_sub_module("question").is_some());
1325    /// ```
1326    #[inline]
1327    pub fn set_sub_module(
1328        &mut self,
1329        name: impl Into<Identifier>,
1330        sub_module: impl Into<SharedModule>,
1331    ) -> &mut Self {
1332        self.modules.insert(name.into(), sub_module.into());
1333        self.flags
1334            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1335        self
1336    }
1337
1338    /// Does the particular Rust function exist in the [`Module`]?
1339    ///
1340    /// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
1341    ///
1342    /// # Example
1343    ///
1344    /// ```
1345    /// # use rhai::Module;
1346    /// let mut module = Module::new();
1347    /// let hash = module.set_native_fn("calc", |x: i64| Ok(42 + x));
1348    /// assert!(module.contains_fn(hash));
1349    /// ```
1350    #[inline]
1351    #[must_use]
1352    pub fn contains_fn(&self, hash_fn: u64) -> bool {
1353        self.functions
1354            .as_ref()
1355            .map_or(false, |m| m.contains_key(&hash_fn))
1356    }
1357
1358    /// _(metadata)_ Update the metadata (parameter names/types, return type and doc-comments) of a registered function.
1359    /// Exported under the `metadata` feature only.
1360    ///
1361    /// # Deprecated
1362    ///
1363    /// This method is deprecated.
1364    /// Use the [`FuncRegistration`] API instead.
1365    ///
1366    /// This method will be removed in the next major version.
1367    #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")]
1368    #[cfg(feature = "metadata")]
1369    #[inline]
1370    pub fn update_fn_metadata_with_comments<A: Into<Identifier>, C: Into<SmartString>>(
1371        &mut self,
1372        hash_fn: u64,
1373        arg_names: impl IntoIterator<Item = A>,
1374        comments: impl IntoIterator<Item = C>,
1375    ) -> &mut Self {
1376        let mut params_info = arg_names
1377            .into_iter()
1378            .map(Into::into)
1379            .collect::<FnArgsVec<_>>();
1380
1381        if let Some((_, f)) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
1382            let (params_info, return_type_name) = if params_info.len() > f.num_params {
1383                let return_type = params_info.pop().unwrap();
1384                (params_info, return_type)
1385            } else {
1386                (params_info, crate::SmartString::new_const())
1387            };
1388            f.params_info = params_info;
1389            f.return_type = return_type_name;
1390            f.comments = comments.into_iter().map(Into::into).collect();
1391        }
1392
1393        self
1394    }
1395
1396    /// Update the namespace of a registered function.
1397    ///
1398    /// # Deprecated
1399    ///
1400    /// This method is deprecated.
1401    /// Use the [`FuncRegistration`] API instead.
1402    ///
1403    /// This method will be removed in the next major version.
1404    #[deprecated(since = "1.17.0", note = "use the `FuncRegistration` API instead")]
1405    #[inline]
1406    pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
1407        if let Some((_, f)) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
1408            f.namespace = namespace;
1409            self.flags
1410                .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1411        }
1412        self
1413    }
1414
1415    /// Remap type ID.
1416    #[inline]
1417    #[must_use]
1418    fn map_type(map: bool, type_id: TypeId) -> TypeId {
1419        if !map {
1420            return type_id;
1421        }
1422        if type_id == TypeId::of::<&str>() {
1423            // Map &str to ImmutableString
1424            return TypeId::of::<ImmutableString>();
1425        }
1426        if type_id == TypeId::of::<String>() {
1427            // Map String to ImmutableString
1428            return TypeId::of::<ImmutableString>();
1429        }
1430
1431        type_id
1432    }
1433
1434    /// Set a native Rust function into the [`Module`] based on a [`FuncRegistration`].
1435    ///
1436    /// # WARNING - Low Level API
1437    ///
1438    /// This function is very low level.  It takes a list of [`TypeId`][std::any::TypeId]'s
1439    /// indicating the actual types of the parameters.
1440    #[inline(always)]
1441    pub fn set_fn_raw_with_options(
1442        &mut self,
1443        options: FuncRegistration,
1444        arg_types: impl AsRef<[TypeId]>,
1445        func: RhaiFunc,
1446    ) -> &FuncMetadata {
1447        options.set_into_module_raw(self, arg_types, func)
1448    }
1449
1450    /// Set a native Rust function into the [`Module`], returning a [`u64`] hash key.
1451    ///
1452    /// If there is a similar existing Rust function, it is replaced.
1453    ///
1454    /// # Use `FuncRegistration` API
1455    ///
1456    /// It is recommended that the [`FuncRegistration`] API be used instead.
1457    ///
1458    /// Essentially, this method is a shortcut for:
1459    ///
1460    /// ```text
1461    /// FuncRegistration::new(name)
1462    ///     .with_namespace(FnNamespace::Internal)
1463    ///     .with_purity(true)
1464    ///     .with_volatility(false)
1465    ///     .set_into_module(module, func)
1466    ///     .hash
1467    /// ```
1468    ///
1469    /// # Assumptions
1470    ///
1471    /// * **Accessibility**: The function namespace is [`FnNamespace::Internal`].
1472    ///
1473    /// * **Purity**: The function is assumed to be _pure_ unless it is a property setter or an index setter.
1474    ///
1475    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
1476    ///
1477    /// * **Metadata**: No metadata for the function is registered.
1478    ///
1479    /// To change these assumptions, use the [`FuncRegistration`] API instead.
1480    ///
1481    /// # Example
1482    ///
1483    /// ```
1484    /// # use rhai::Module;
1485    /// let mut module = Module::new();
1486    /// let hash = module.set_native_fn("calc", |x: i64| Ok(42 + x));
1487    /// assert!(module.contains_fn(hash));
1488    /// ```
1489    #[inline]
1490    pub fn set_native_fn<A: 'static, const N: usize, const X: bool, R, FUNC>(
1491        &mut self,
1492        name: impl Into<Identifier>,
1493        func: FUNC,
1494    ) -> u64
1495    where
1496        R: Variant + Clone,
1497        FUNC: RhaiNativeFunc<A, N, X, R, true> + SendSync + 'static,
1498    {
1499        FuncRegistration::new(name)
1500            .with_namespace(FnNamespace::Internal)
1501            .with_purity(true)
1502            .with_volatility(false)
1503            .set_into_module(self, func)
1504            .hash
1505    }
1506
1507    /// Set a Rust getter function taking one mutable parameter, returning a [`u64`] hash key.
1508    /// This function is automatically exposed to the global namespace.
1509    ///
1510    /// If there is a similar existing Rust getter function, it is replaced.
1511    ///
1512    /// # Assumptions
1513    ///
1514    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
1515    ///
1516    /// * **Purity**: The function is assumed to be _pure_ (so it can be called on constants).
1517    ///
1518    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
1519    ///
1520    /// * **Metadata**: No metadata for the function is registered.
1521    ///
1522    /// To change these assumptions, use the [`FuncRegistration`] API instead.
1523    ///
1524    /// # Example
1525    ///
1526    /// ```
1527    /// # use rhai::Module;
1528    /// let mut module = Module::new();
1529    /// let hash = module.set_getter_fn("value", |x: &mut i64| Ok(*x));
1530    /// assert!(module.contains_fn(hash));
1531    /// ```
1532    #[cfg(not(feature = "no_object"))]
1533    #[inline(always)]
1534    pub fn set_getter_fn<A, const X: bool, R, FUNC>(
1535        &mut self,
1536        name: impl AsRef<str>,
1537        func: FUNC,
1538    ) -> u64
1539    where
1540        A: Variant + Clone,
1541        R: Variant + Clone,
1542        FUNC: RhaiNativeFunc<(Mut<A>,), 1, X, R, true> + SendSync + 'static,
1543    {
1544        FuncRegistration::new(crate::engine::make_getter(name.as_ref()))
1545            .with_namespace(FnNamespace::Global)
1546            .with_purity(true)
1547            .with_volatility(false)
1548            .set_into_module(self, func)
1549            .hash
1550    }
1551
1552    /// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`],
1553    /// returning a [`u64`] hash key.
1554    /// This function is automatically exposed to the global namespace.
1555    ///
1556    /// If there is a similar existing setter Rust function, it is replaced.
1557    ///
1558    /// # Assumptions
1559    ///
1560    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
1561    ///
1562    /// * **Purity**: The function is assumed to be _non-pure_ (so it cannot be called on constants).
1563    ///
1564    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
1565    ///
1566    /// * **Metadata**: No metadata for the function is registered.
1567    ///
1568    /// To change these assumptions, use the [`FuncRegistration`] API instead.
1569    ///
1570    /// # Example
1571    ///
1572    /// ```
1573    /// use rhai::{Module, ImmutableString};
1574    ///
1575    /// let mut module = Module::new();
1576    /// let hash = module.set_setter_fn("value", |x: &mut i64, y: ImmutableString| {
1577    ///                 *x = y.len() as i64; Ok(())
1578    /// });
1579    /// assert!(module.contains_fn(hash));
1580    /// ```
1581    #[cfg(not(feature = "no_object"))]
1582    #[inline(always)]
1583    pub fn set_setter_fn<A, const X: bool, R, FUNC>(
1584        &mut self,
1585        name: impl AsRef<str>,
1586        func: FUNC,
1587    ) -> u64
1588    where
1589        A: Variant + Clone,
1590        R: Variant + Clone,
1591        FUNC: RhaiNativeFunc<(Mut<A>, R), 2, X, (), true> + SendSync + 'static,
1592    {
1593        FuncRegistration::new(crate::engine::make_setter(name.as_ref()))
1594            .with_namespace(FnNamespace::Global)
1595            .with_purity(false)
1596            .with_volatility(false)
1597            .set_into_module(self, func)
1598            .hash
1599    }
1600
1601    /// Set a pair of Rust getter and setter functions into the [`Module`], returning both [`u64`] hash keys.
1602    /// This is a short-hand for [`set_getter_fn`][Module::set_getter_fn] and [`set_setter_fn`][Module::set_setter_fn].
1603    ///
1604    /// These function are automatically exposed to the global namespace.
1605    ///
1606    /// If there are similar existing Rust functions, they are replaced.
1607    ///
1608    /// To change these assumptions, use the [`FuncRegistration`] API instead.
1609    ///
1610    /// # Example
1611    ///
1612    /// ```
1613    /// use rhai::{Module, ImmutableString};
1614    ///
1615    /// let mut module = Module::new();
1616    /// let (hash_get, hash_set) =
1617    ///         module.set_getter_setter_fn("value",
1618    ///                 |x: &mut i64| Ok(x.to_string().into()),
1619    ///                 |x: &mut i64, y: ImmutableString| { *x = y.len() as i64; Ok(()) }
1620    ///         );
1621    /// assert!(module.contains_fn(hash_get));
1622    /// assert!(module.contains_fn(hash_set));
1623    /// ```
1624    #[cfg(not(feature = "no_object"))]
1625    #[inline(always)]
1626    pub fn set_getter_setter_fn<
1627        A: Variant + Clone,
1628        const X1: bool,
1629        const X2: bool,
1630        R: Variant + Clone,
1631    >(
1632        &mut self,
1633        name: impl AsRef<str>,
1634        getter: impl RhaiNativeFunc<(Mut<A>,), 1, X1, R, true> + SendSync + 'static,
1635        setter: impl RhaiNativeFunc<(Mut<A>, R), 2, X2, (), true> + SendSync + 'static,
1636    ) -> (u64, u64) {
1637        (
1638            self.set_getter_fn(name.as_ref(), getter),
1639            self.set_setter_fn(name.as_ref(), setter),
1640        )
1641    }
1642
1643    /// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`],
1644    /// returning a [`u64`] hash key.
1645    /// This function is automatically exposed to the global namespace.
1646    ///
1647    /// If there is a similar existing setter Rust function, it is replaced.
1648    ///
1649    /// # Assumptions
1650    ///
1651    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
1652    ///
1653    /// * **Purity**: The function is assumed to be _pure_ (so it can be called on constants).
1654    ///
1655    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
1656    ///
1657    /// * **Metadata**: No metadata for the function is registered.
1658    ///
1659    /// To change these assumptions, use the [`FuncRegistration`] API instead.
1660    ///
1661    /// # Panics
1662    ///
1663    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
1664    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
1665    ///
1666    /// Indexers for arrays, object maps, strings and integers cannot be registered.
1667    ///
1668    /// # Example
1669    ///
1670    /// ```
1671    /// use rhai::{Module, ImmutableString};
1672    ///
1673    /// #[derive(Clone)]
1674    /// struct TestStruct(i64);
1675    ///
1676    /// let mut module = Module::new();
1677    ///
1678    /// let hash = module.set_indexer_get_fn(
1679    ///                 |x: &mut TestStruct, y: ImmutableString| Ok(x.0 + y.len() as i64)
1680    ///            );
1681    ///
1682    /// assert!(module.contains_fn(hash));
1683    /// ```
1684    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
1685    #[inline]
1686    pub fn set_indexer_get_fn<A, B, const X: bool, R, FUNC>(&mut self, func: FUNC) -> u64
1687    where
1688        A: Variant + Clone,
1689        B: Variant + Clone,
1690        R: Variant + Clone,
1691        FUNC: RhaiNativeFunc<(Mut<A>, B), 2, X, R, true> + SendSync + 'static,
1692    {
1693        FuncRegistration::new(crate::engine::FN_IDX_GET)
1694            .with_namespace(FnNamespace::Global)
1695            .with_purity(true)
1696            .with_volatility(false)
1697            .set_into_module(self, func)
1698            .hash
1699    }
1700
1701    /// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`],
1702    /// returning a [`u64`] hash key.
1703    /// This function is automatically exposed to the global namespace.
1704    ///
1705    /// If there is a similar existing Rust function, it is replaced.
1706    ///
1707    /// # Assumptions
1708    ///
1709    /// * **Accessibility**: The function namespace is [`FnNamespace::Global`].
1710    ///
1711    /// * **Purity**: The function is assumed to be _non-pure_ (so it cannot be called on constants).
1712    ///
1713    /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
1714    ///
1715    /// # Panics
1716    ///
1717    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
1718    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
1719    ///
1720    /// Indexers for arrays, object maps, strings and integers cannot be registered.
1721    ///
1722    /// # Example
1723    ///
1724    /// ```
1725    /// use rhai::{Module, ImmutableString};
1726    ///
1727    /// #[derive(Clone)]
1728    /// struct TestStruct(i64);
1729    ///
1730    /// let mut module = Module::new();
1731    ///
1732    /// let hash = module.set_indexer_set_fn(|x: &mut TestStruct, y: ImmutableString, value: i64| {
1733    ///                         *x = TestStruct(y.len() as i64 + value);
1734    ///                         Ok(())
1735    ///            });
1736    ///
1737    /// assert!(module.contains_fn(hash));
1738    /// ```
1739    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
1740    #[inline]
1741    pub fn set_indexer_set_fn<A, B, const X: bool, R, FUNC>(&mut self, func: FUNC) -> u64
1742    where
1743        A: Variant + Clone,
1744        B: Variant + Clone,
1745        R: Variant + Clone,
1746        FUNC: RhaiNativeFunc<(Mut<A>, B, R), 3, X, (), true> + SendSync + 'static,
1747    {
1748        FuncRegistration::new(crate::engine::FN_IDX_SET)
1749            .with_namespace(FnNamespace::Global)
1750            .with_purity(false)
1751            .with_volatility(false)
1752            .set_into_module(self, func)
1753            .hash
1754    }
1755
1756    /// Set a pair of Rust index getter and setter functions into the [`Module`], returning both [`u64`] hash keys.
1757    /// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and
1758    /// [`set_indexer_set_fn`][Module::set_indexer_set_fn].
1759    ///
1760    /// These functions are automatically exposed to the global namespace.
1761    ///
1762    /// If there are similar existing Rust functions, they are replaced.
1763    ///
1764    /// # Panics
1765    ///
1766    /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
1767    /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
1768    ///
1769    /// Indexers for arrays, object maps, strings and integers cannot be registered.
1770    ///
1771    /// # Example
1772    ///
1773    /// ```
1774    /// use rhai::{Module, ImmutableString};
1775    ///
1776    /// #[derive(Clone)]
1777    /// struct TestStruct(i64);
1778    ///
1779    /// let mut module = Module::new();
1780    ///
1781    /// let (hash_get, hash_set) = module.set_indexer_get_set_fn(
1782    ///     |x: &mut TestStruct, y: ImmutableString| Ok(x.0 + y.len() as i64),
1783    ///     |x: &mut TestStruct, y: ImmutableString, value: i64| { *x = TestStruct(y.len() as i64 + value); Ok(()) }
1784    /// );
1785    ///
1786    /// assert!(module.contains_fn(hash_get));
1787    /// assert!(module.contains_fn(hash_set));
1788    /// ```
1789    #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
1790    #[inline(always)]
1791    pub fn set_indexer_get_set_fn<
1792        A: Variant + Clone,
1793        B: Variant + Clone,
1794        const X1: bool,
1795        const X2: bool,
1796        R: Variant + Clone,
1797    >(
1798        &mut self,
1799        get_fn: impl RhaiNativeFunc<(Mut<A>, B), 2, X1, R, true> + SendSync + 'static,
1800        set_fn: impl RhaiNativeFunc<(Mut<A>, B, R), 3, X2, (), true> + SendSync + 'static,
1801    ) -> (u64, u64) {
1802        (
1803            self.set_indexer_get_fn(get_fn),
1804            self.set_indexer_set_fn(set_fn),
1805        )
1806    }
1807
1808    /// Look up a native Rust function by hash.
1809    #[inline]
1810    #[must_use]
1811    pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&RhaiFunc> {
1812        self.functions
1813            .as_ref()
1814            .and_then(|m| m.get(&hash_native))
1815            .map(|(f, _)| f)
1816    }
1817
1818    /// Can the particular function with [`Dynamic`] parameter(s) exist in the [`Module`]?
1819    ///
1820    /// A `true` return value does not automatically imply that the function _must_ exist.
1821    #[inline(always)]
1822    #[must_use]
1823    pub(crate) const fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool {
1824        !self.dynamic_functions_filter.is_absent(hash_script)
1825    }
1826
1827    /// Does the particular namespace-qualified function exist in the [`Module`]?
1828    ///
1829    /// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
1830    #[inline(always)]
1831    #[must_use]
1832    pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
1833        self.all_functions
1834            .as_ref()
1835            .map_or(false, |m| m.contains_key(&hash_fn))
1836    }
1837
1838    /// Get a namespace-qualified function.
1839    ///
1840    /// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
1841    #[cfg(not(feature = "no_module"))]
1842    #[inline]
1843    #[must_use]
1844    pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&RhaiFunc> {
1845        self.all_functions
1846            .as_ref()
1847            .and_then(|m| m.get(&hash_qualified_fn))
1848    }
1849
1850    /// Combine another [`Module`] into this [`Module`].
1851    /// The other [`Module`] is _consumed_ to merge into this [`Module`].
1852    #[inline]
1853    pub fn combine(&mut self, other: Self) -> &mut Self {
1854        self.modules.extend(other.modules);
1855        self.variables.extend(other.variables);
1856        match self.functions {
1857            Some(ref mut m) if other.functions.is_some() => m.extend(other.functions.unwrap()),
1858            Some(_) => (),
1859            None => self.functions = other.functions,
1860        }
1861        self.dynamic_functions_filter += other.dynamic_functions_filter;
1862        self.type_iterators.extend(other.type_iterators);
1863        self.all_functions = None;
1864        self.all_variables = None;
1865        self.all_type_iterators.clear();
1866        self.flags
1867            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1868
1869        #[cfg(feature = "metadata")]
1870        {
1871            if !self.doc.is_empty() {
1872                self.doc.push('\n');
1873            }
1874            self.doc.push_str(&other.doc);
1875        }
1876
1877        self
1878    }
1879
1880    /// Combine another [`Module`] into this [`Module`].
1881    /// The other [`Module`] is _consumed_ to merge into this [`Module`].
1882    /// Sub-modules are flattened onto the root [`Module`], with higher level overriding lower level.
1883    #[inline]
1884    pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
1885        for m in other.modules.into_values() {
1886            self.combine_flatten(shared_take_or_clone(m));
1887        }
1888        self.variables.extend(other.variables);
1889        match self.functions {
1890            Some(ref mut m) if other.functions.is_some() => m.extend(other.functions.unwrap()),
1891            Some(_) => (),
1892            None => self.functions = other.functions,
1893        }
1894        self.dynamic_functions_filter += other.dynamic_functions_filter;
1895        self.type_iterators.extend(other.type_iterators);
1896        self.all_functions = None;
1897        self.all_variables = None;
1898        self.all_type_iterators.clear();
1899        self.flags
1900            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1901
1902        #[cfg(feature = "metadata")]
1903        {
1904            if !self.doc.is_empty() {
1905                self.doc.push('\n');
1906            }
1907            self.doc.push_str(&other.doc);
1908        }
1909
1910        self
1911    }
1912
1913    /// Polyfill this [`Module`] with another [`Module`].
1914    /// Only items not existing in this [`Module`] are added.
1915    #[inline]
1916    pub fn fill_with(&mut self, other: &Self) -> &mut Self {
1917        for (k, v) in &other.modules {
1918            if !self.modules.contains_key(k) {
1919                self.modules.insert(k.clone(), v.clone());
1920            }
1921        }
1922        for (k, v) in &other.variables {
1923            if !self.variables.contains_key(k) {
1924                self.variables.insert(k.clone(), v.clone());
1925            }
1926        }
1927        if let Some(ref functions) = other.functions {
1928            let others_len = functions.len();
1929
1930            for (&k, f) in functions {
1931                let map = self
1932                    .functions
1933                    .get_or_insert_with(|| new_hash_map(FN_MAP_SIZE));
1934                map.reserve(others_len);
1935                map.entry(k).or_insert_with(|| f.clone());
1936            }
1937        }
1938        self.dynamic_functions_filter += &other.dynamic_functions_filter;
1939        for (&k, v) in &other.type_iterators {
1940            self.type_iterators.entry(k).or_insert_with(|| v.clone());
1941        }
1942
1943        self.all_functions = None;
1944        self.all_variables = None;
1945        self.all_type_iterators.clear();
1946        self.flags
1947            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
1948
1949        #[cfg(feature = "metadata")]
1950        {
1951            if !self.doc.is_empty() {
1952                self.doc.push('\n');
1953            }
1954            self.doc.push_str(&other.doc);
1955        }
1956
1957        self
1958    }
1959
1960    /// Merge another [`Module`] into this [`Module`].
1961    #[inline(always)]
1962    pub fn merge(&mut self, other: &Self) -> &mut Self {
1963        self.merge_filtered(other, |_, _, _, _, _| true)
1964    }
1965
1966    /// Merge another [`Module`] into this [`Module`] based on a filter predicate.
1967    pub(crate) fn merge_filtered(
1968        &mut self,
1969        other: &Self,
1970        _filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool + Copy,
1971    ) -> &mut Self {
1972        for (k, v) in &other.modules {
1973            let mut m = Self::new();
1974            m.merge_filtered(v, _filter);
1975            self.set_sub_module(k.clone(), m);
1976        }
1977        #[cfg(feature = "no_function")]
1978        self.modules.extend(other.modules.clone());
1979
1980        self.variables.extend(other.variables.clone());
1981
1982        if let Some(ref functions) = other.functions {
1983            match self.functions {
1984                Some(ref mut m) => m.extend(
1985                    functions
1986                        .iter()
1987                        .filter(|(.., (f, m))| {
1988                            _filter(m.namespace, m.access, f.is_script(), &m.name, m.num_params)
1989                        })
1990                        .map(|(&k, f)| (k, f.clone())),
1991                ),
1992                None => self.functions = other.functions.clone(),
1993            }
1994        }
1995        self.dynamic_functions_filter += &other.dynamic_functions_filter;
1996
1997        self.type_iterators.extend(other.type_iterators.clone());
1998        self.all_functions = None;
1999        self.all_variables = None;
2000        self.all_type_iterators.clear();
2001        self.flags
2002            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
2003
2004        #[cfg(feature = "metadata")]
2005        {
2006            if !self.doc.is_empty() {
2007                self.doc.push('\n');
2008            }
2009            self.doc.push_str(&other.doc);
2010        }
2011
2012        self
2013    }
2014
2015    /// Filter out the functions, retaining only some script-defined functions based on a filter predicate.
2016    #[cfg(not(feature = "no_function"))]
2017    #[inline]
2018    pub(crate) fn retain_script_functions(
2019        &mut self,
2020        filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
2021    ) -> &mut Self {
2022        self.functions = std::mem::take(&mut self.functions).map(|m| {
2023            m.into_iter()
2024                .filter(|(.., (f, m))| {
2025                    if f.is_script() {
2026                        filter(m.namespace, m.access, &m.name, m.num_params)
2027                    } else {
2028                        false
2029                    }
2030                })
2031                .collect()
2032        });
2033
2034        self.dynamic_functions_filter.clear();
2035        self.all_functions = None;
2036        self.all_variables = None;
2037        self.all_type_iterators.clear();
2038        self.flags
2039            .remove(ModuleFlags::INDEXED | ModuleFlags::INDEXED_GLOBAL_FUNCTIONS);
2040        self
2041    }
2042
2043    /// Get the number of variables, functions and type iterators in the [`Module`].
2044    #[inline(always)]
2045    #[must_use]
2046    pub fn count(&self) -> (usize, usize, usize) {
2047        (
2048            self.variables.len(),
2049            self.functions.as_ref().map_or(0, StraightHashMap::len),
2050            self.type_iterators.len(),
2051        )
2052    }
2053
2054    /// Get an iterator to the sub-modules in the [`Module`].
2055    #[inline(always)]
2056    pub fn iter_sub_modules(&self) -> impl Iterator<Item = (&str, &SharedModule)> {
2057        self.iter_sub_modules_raw().map(|(k, m)| (k.as_str(), m))
2058    }
2059    /// Get an iterator to the sub-modules in the [`Module`].
2060    #[inline(always)]
2061    pub(crate) fn iter_sub_modules_raw(
2062        &self,
2063    ) -> impl Iterator<Item = (&Identifier, &SharedModule)> {
2064        self.modules.iter()
2065    }
2066
2067    /// Get an iterator to the variables in the [`Module`].
2068    #[inline(always)]
2069    pub fn iter_var(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
2070        self.iter_var_raw().map(|(k, v)| (k.as_str(), v))
2071    }
2072    /// Get an iterator to the variables in the [`Module`].
2073    #[inline(always)]
2074    pub(crate) fn iter_var_raw(&self) -> impl Iterator<Item = (&Identifier, &Dynamic)> {
2075        self.variables.iter()
2076    }
2077
2078    /// Get an iterator to the custom types in the [`Module`].
2079    #[inline(always)]
2080    #[allow(dead_code)]
2081    pub(crate) fn iter_custom_types(&self) -> impl Iterator<Item = (&str, &CustomTypeInfo)> {
2082        self.custom_types.iter()
2083    }
2084
2085    /// Get an iterator to the functions in the [`Module`].
2086    #[inline]
2087    #[allow(dead_code)]
2088    pub(crate) fn iter_fn(&self) -> impl Iterator<Item = (&RhaiFunc, &FuncMetadata)> {
2089        self.functions
2090            .iter()
2091            .flat_map(StraightHashMap::values)
2092            .map(|(f, m)| (f, &**m))
2093    }
2094
2095    /// Get an iterator over all script-defined functions in the [`Module`].
2096    ///
2097    /// Function metadata includes:
2098    /// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
2099    /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
2100    /// 3) Function name (as string slice).
2101    /// 4) Number of parameters.
2102    /// 5) Shared reference to function definition [`ScriptFuncDef`][crate::ast::ScriptFuncDef].
2103    #[cfg(not(feature = "no_function"))]
2104    #[inline]
2105    pub(crate) fn iter_script_fn(
2106        &self,
2107    ) -> impl Iterator<
2108        Item = (
2109            FnNamespace,
2110            FnAccess,
2111            &str,
2112            usize,
2113            &Shared<crate::ast::ScriptFuncDef>,
2114        ),
2115    > + '_ {
2116        self.iter_fn().filter(|(f, _)| f.is_script()).map(|(f, m)| {
2117            (
2118                m.namespace,
2119                m.access,
2120                m.name.as_str(),
2121                m.num_params,
2122                f.get_script_fn_def().expect("`ScriptFuncDef`"),
2123            )
2124        })
2125    }
2126
2127    /// Get an iterator over all script-defined functions in the [`Module`].
2128    ///
2129    /// Function metadata includes:
2130    /// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
2131    /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
2132    /// 3) Function name (as string slice).
2133    /// 4) Number of parameters.
2134    #[cfg(not(feature = "no_function"))]
2135    #[cfg(not(feature = "internals"))]
2136    #[inline]
2137    pub fn iter_script_fn_info(
2138        &self,
2139    ) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> {
2140        self.iter_fn()
2141            .filter(|(f, _)| f.is_script())
2142            .map(|(_, f)| (f.namespace, f.access, f.name.as_str(), f.num_params))
2143    }
2144
2145    /// _(internals)_ Get an iterator over all script-defined functions in the [`Module`].
2146    /// Exported under the `internals` feature only.
2147    ///
2148    /// Function metadata includes:
2149    /// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
2150    /// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
2151    /// 3) Function name (as string slice).
2152    /// 4) Number of parameters.
2153    /// 5) _(internals)_ Shared reference to function definition [`ScriptFuncDef`][crate::ast::ScriptFuncDef].
2154    #[cfg(not(feature = "no_function"))]
2155    #[cfg(feature = "internals")]
2156    #[inline(always)]
2157    pub fn iter_script_fn_info(
2158        &self,
2159    ) -> impl Iterator<
2160        Item = (
2161            FnNamespace,
2162            FnAccess,
2163            &str,
2164            usize,
2165            &Shared<crate::ast::ScriptFuncDef>,
2166        ),
2167    > {
2168        self.iter_script_fn()
2169    }
2170
2171    /// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
2172    ///
2173    /// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions to
2174    /// cross-call each other.
2175    ///
2176    /// # Example
2177    ///
2178    /// ```
2179    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2180    /// use rhai::{Engine, Module, Scope};
2181    ///
2182    /// let engine = Engine::new();
2183    /// let ast = engine.compile("let answer = 42; export answer;")?;
2184    /// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
2185    /// assert!(module.contains_var("answer"));
2186    /// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
2187    /// # Ok(())
2188    /// # }
2189    /// ```
2190    #[cfg(not(feature = "no_module"))]
2191    #[inline(always)]
2192    pub fn eval_ast_as_new(
2193        scope: crate::Scope,
2194        ast: &crate::AST,
2195        engine: &crate::Engine,
2196    ) -> RhaiResultOf<Self> {
2197        let mut scope = scope;
2198        let global = &mut crate::eval::GlobalRuntimeState::new(engine);
2199
2200        Self::eval_ast_as_new_raw(engine, &mut scope, global, ast)
2201    }
2202    /// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
2203    ///
2204    /// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions to
2205    /// cross-call each other.
2206    ///
2207    /// # WARNING - Low Level API
2208    ///
2209    /// This function is very low level.
2210    ///
2211    /// In particular, the [`global`][crate::GlobalRuntimeState] parameter allows the entire
2212    /// calling environment to be encapsulated, including automatic global constants.
2213    #[cfg(not(feature = "no_module"))]
2214    pub fn eval_ast_as_new_raw(
2215        engine: &crate::Engine,
2216        scope: &mut crate::Scope,
2217        global: &mut crate::eval::GlobalRuntimeState,
2218        ast: &crate::AST,
2219    ) -> RhaiResultOf<Self> {
2220        // Save global state
2221        let orig_scope_len = scope.len();
2222        let orig_imports_len = global.num_imports();
2223        let orig_source = global.source.clone();
2224
2225        #[cfg(not(feature = "no_function"))]
2226        let orig_lib_len = global.lib.len();
2227
2228        #[cfg(not(feature = "no_function"))]
2229        let orig_constants = std::mem::take(&mut global.constants);
2230
2231        // Run the script
2232        let caches = &mut crate::eval::Caches::new();
2233
2234        let result = engine.eval_ast_with_scope_raw(global, caches, scope, ast);
2235
2236        // Create new module
2237        let mut module = Self::new();
2238
2239        // Extra modules left become sub-modules
2240        let mut imports = crate::ThinVec::new();
2241
2242        if result.is_ok() {
2243            global
2244                .scan_imports_raw()
2245                .skip(orig_imports_len)
2246                .for_each(|(k, m)| {
2247                    imports.push((k.clone(), m.clone()));
2248                    module.set_sub_module(k.clone(), m.clone());
2249                });
2250        }
2251
2252        // Restore global state
2253        #[cfg(not(feature = "no_function"))]
2254        let constants = std::mem::replace(&mut global.constants, orig_constants);
2255
2256        global.truncate_imports(orig_imports_len);
2257
2258        #[cfg(not(feature = "no_function"))]
2259        global.lib.truncate(orig_lib_len);
2260
2261        global.source = orig_source;
2262
2263        // The return value is thrown away and not used
2264        let _ = result?;
2265
2266        // Encapsulated environment
2267        let environ = Shared::new(crate::ast::EncapsulatedEnviron {
2268            #[cfg(not(feature = "no_function"))]
2269            lib: ast.shared_lib().clone(),
2270            imports,
2271            #[cfg(not(feature = "no_function"))]
2272            constants,
2273        });
2274
2275        // Variables with an alias left in the scope become module variables
2276        let mut i = scope.len();
2277        while i > 0 {
2278            i -= 1;
2279
2280            let (mut value, mut aliases) = if i >= orig_scope_len {
2281                let (_, v, a) = scope.pop_entry().unwrap();
2282                (v, a)
2283            } else {
2284                let (_, v, a) = scope.get_entry_by_index(i);
2285                (v.clone(), a.to_vec())
2286            };
2287
2288            value.deep_scan(|v| {
2289                if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
2290                    fn_ptr.environ = Some(environ.clone());
2291                }
2292            });
2293
2294            match aliases.len() {
2295                0 => (),
2296                1 => {
2297                    let alias = aliases.pop().unwrap();
2298                    if !module.contains_var(&alias) {
2299                        module.set_var(alias, value);
2300                    }
2301                }
2302                _ => {
2303                    // Avoid cloning the last value
2304                    let mut first_alias = None;
2305
2306                    for alias in aliases {
2307                        if module.contains_var(&alias) {
2308                            continue;
2309                        }
2310                        if first_alias.is_none() {
2311                            first_alias = Some(alias);
2312                        } else {
2313                            module.set_var(alias, value.clone());
2314                        }
2315                    }
2316
2317                    if let Some(alias) = first_alias {
2318                        module.set_var(alias, value);
2319                    }
2320                }
2321            }
2322        }
2323
2324        // Non-private functions defined become module functions
2325        #[cfg(not(feature = "no_function"))]
2326        ast.iter_fn_def()
2327            .filter(|&f| match f.access {
2328                FnAccess::Public => true,
2329                FnAccess::Private => false,
2330            })
2331            .for_each(|f| {
2332                let hash = module.set_script_fn(f.clone());
2333                if let (
2334                    RhaiFunc::Script {
2335                        environ: ref mut e, ..
2336                    },
2337                    _,
2338                ) = module.functions.as_mut().unwrap().get_mut(&hash).unwrap()
2339                {
2340                    // Encapsulate AST environment
2341                    *e = Some(environ.clone());
2342                }
2343            });
2344
2345        module.id = ast.source_raw().cloned();
2346
2347        #[cfg(feature = "metadata")]
2348        module.set_doc(ast.doc());
2349
2350        module.build_index();
2351
2352        Ok(module)
2353    }
2354
2355    /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
2356    ///
2357    /// # Panics
2358    ///
2359    /// Panics if the [`Module`] is not yet indexed via [`build_index`][Module::build_index].
2360    #[inline(always)]
2361    #[must_use]
2362    pub const fn contains_indexed_global_functions(&self) -> bool {
2363        self.flags.intersects(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS)
2364    }
2365
2366    /// Scan through all the sub-modules in the [`Module`] and build a hash index of all
2367    /// variables and functions as one flattened namespace.
2368    ///
2369    /// If the [`Module`] is already indexed, this method has no effect.
2370    pub fn build_index(&mut self) -> &mut Self {
2371        // Collect a particular module.
2372        fn index_module<'a>(
2373            module: &'a Module,
2374            path: &mut Vec<&'a str>,
2375            variables: &mut StraightHashMap<Dynamic>,
2376            functions: &mut StraightHashMap<RhaiFunc>,
2377            type_iterators: &mut BTreeMap<TypeId, Shared<FnIterator>>,
2378        ) -> bool {
2379            let mut contains_indexed_global_functions = false;
2380
2381            for (name, m) in &module.modules {
2382                // Index all the sub-modules first.
2383                path.push(name);
2384                if index_module(m, path, variables, functions, type_iterators) {
2385                    contains_indexed_global_functions = true;
2386                }
2387                path.pop();
2388            }
2389
2390            // Index all variables
2391            for (var_name, value) in &module.variables {
2392                let hash_var = crate::calc_var_hash(path.iter().copied(), var_name);
2393
2394                // Catch hash collisions in testing environment only.
2395                #[cfg(feature = "testing-environ")]
2396                assert!(
2397                    !variables.contains_key(&hash_var),
2398                    "Hash {} already exists when indexing variable {}",
2399                    hash_var,
2400                    var_name
2401                );
2402
2403                variables.insert(hash_var, value.clone());
2404            }
2405
2406            // Index all type iterators
2407            for (&type_id, func) in &module.type_iterators {
2408                type_iterators.insert(type_id, func.clone());
2409            }
2410
2411            // Index all functions
2412            for (&hash, (f, m)) in module.functions.iter().flatten() {
2413                match m.namespace {
2414                    FnNamespace::Global => {
2415                        // Catch hash collisions in testing environment only.
2416                        #[cfg(feature = "testing-environ")]
2417                        if let Some(fx) = functions.get(&hash) {
2418                            unreachable!(
2419                                "Hash {} already exists when indexing function {:#?}:\n{:#?}",
2420                                hash, f, fx
2421                            );
2422                        }
2423
2424                        // Flatten all functions with global namespace
2425                        functions.insert(hash, f.clone());
2426                        contains_indexed_global_functions = true;
2427                    }
2428                    FnNamespace::Internal => (),
2429                }
2430                match m.access {
2431                    FnAccess::Public => (),
2432                    FnAccess::Private => continue, // Do not index private functions
2433                }
2434
2435                if f.is_script() {
2436                    #[cfg(not(feature = "no_function"))]
2437                    {
2438                        let hash_script =
2439                            crate::calc_fn_hash(path.iter().copied(), &m.name, m.num_params);
2440                        #[cfg(not(feature = "no_object"))]
2441                        let hash_script = f
2442                            .get_script_fn_def()
2443                            .unwrap()
2444                            .this_type
2445                            .as_ref()
2446                            .map_or(hash_script, |this_type| {
2447                                crate::calc_typed_method_hash(hash_script, this_type)
2448                            });
2449
2450                        // Catch hash collisions in testing environment only.
2451                        #[cfg(feature = "testing-environ")]
2452                        if let Some(fx) = functions.get(&hash_script) {
2453                            unreachable!(
2454                                "Hash {} already exists when indexing function {:#?}:\n{:#?}",
2455                                hash_script, f, fx
2456                            );
2457                        }
2458
2459                        functions.insert(hash_script, f.clone());
2460                    }
2461                } else {
2462                    let hash_fn =
2463                        calc_native_fn_hash(path.iter().copied(), &m.name, &m.param_types);
2464
2465                    // Catch hash collisions in testing environment only.
2466                    #[cfg(feature = "testing-environ")]
2467                    if let Some(fx) = functions.get(&hash_fn) {
2468                        unreachable!(
2469                            "Hash {} already exists when indexing function {:#?}:\n{:#?}",
2470                            hash_fn, f, fx
2471                        );
2472                    }
2473
2474                    functions.insert(hash_fn, f.clone());
2475                }
2476            }
2477
2478            contains_indexed_global_functions
2479        }
2480
2481        if !self.is_indexed() {
2482            let mut path = Vec::with_capacity(4);
2483            let mut variables = new_hash_map(self.variables.len());
2484            let mut functions =
2485                new_hash_map(self.functions.as_ref().map_or(0, StraightHashMap::len));
2486            let mut type_iterators = BTreeMap::new();
2487
2488            path.push("");
2489
2490            let has_global_functions = index_module(
2491                self,
2492                &mut path,
2493                &mut variables,
2494                &mut functions,
2495                &mut type_iterators,
2496            );
2497
2498            self.flags
2499                .set(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS, has_global_functions);
2500
2501            self.all_variables = (!variables.is_empty()).then_some(variables);
2502            self.all_functions = (!functions.is_empty()).then_some(functions);
2503            self.all_type_iterators = type_iterators;
2504
2505            self.flags |= ModuleFlags::INDEXED;
2506        }
2507
2508        self
2509    }
2510
2511    /// Does a type iterator exist in the entire module tree?
2512    #[inline(always)]
2513    #[must_use]
2514    pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
2515        self.all_type_iterators.contains_key(&id)
2516    }
2517
2518    /// Does a type iterator exist in the module?
2519    #[inline(always)]
2520    #[must_use]
2521    pub fn contains_iter(&self, id: TypeId) -> bool {
2522        self.type_iterators.contains_key(&id)
2523    }
2524
2525    /// Set a type iterator into the [`Module`].
2526    #[inline(always)]
2527    pub fn set_iter(
2528        &mut self,
2529        type_id: TypeId,
2530        func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + SendSync + 'static,
2531    ) -> &mut Self {
2532        self.set_iter_result(type_id, move |x| {
2533            Box::new(func(x).map(Ok)) as Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>
2534        })
2535    }
2536
2537    /// Set a fallible type iterator into the [`Module`].
2538    #[inline]
2539    pub fn set_iter_result(
2540        &mut self,
2541        type_id: TypeId,
2542        func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + SendSync + 'static,
2543    ) -> &mut Self {
2544        let func = Shared::new(func);
2545        if self.is_indexed() {
2546            self.all_type_iterators.insert(type_id, func.clone());
2547        }
2548        self.type_iterators.insert(type_id, func);
2549        self
2550    }
2551
2552    /// Set a type iterator into the [`Module`].
2553    #[inline(always)]
2554    pub fn set_iterable<T>(&mut self) -> &mut Self
2555    where
2556        T: Variant + Clone + IntoIterator,
2557        <T as IntoIterator>::Item: Variant + Clone,
2558    {
2559        self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
2560            Box::new(obj.cast::<T>().into_iter().map(Dynamic::from))
2561        })
2562    }
2563
2564    /// Set a fallible type iterator into the [`Module`].
2565    #[inline(always)]
2566    pub fn set_iterable_result<T, X>(&mut self) -> &mut Self
2567    where
2568        T: Variant + Clone + IntoIterator<Item = RhaiResultOf<X>>,
2569        X: Variant + Clone,
2570    {
2571        self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
2572            Box::new(obj.cast::<T>().into_iter().map(|v| v.map(Dynamic::from)))
2573        })
2574    }
2575
2576    /// Set an iterator type into the [`Module`] as a type iterator.
2577    #[inline(always)]
2578    pub fn set_iterator<T>(&mut self) -> &mut Self
2579    where
2580        T: Variant + Clone + Iterator,
2581        <T as Iterator>::Item: Variant + Clone,
2582    {
2583        self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
2584            Box::new(obj.cast::<T>().map(Dynamic::from))
2585        })
2586    }
2587
2588    /// Set a iterator type into the [`Module`] as a fallible type iterator.
2589    #[inline(always)]
2590    pub fn set_iterator_result<T, X>(&mut self) -> &mut Self
2591    where
2592        T: Variant + Clone + Iterator<Item = RhaiResultOf<X>>,
2593        X: Variant + Clone,
2594    {
2595        self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
2596            Box::new(obj.cast::<T>().map(|v| v.map(Dynamic::from)))
2597        })
2598    }
2599
2600    /// Get the specified type iterator.
2601    #[cfg(not(feature = "no_module"))]
2602    #[inline]
2603    #[must_use]
2604    pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&FnIterator> {
2605        self.all_type_iterators.get(&id).map(|f| &**f)
2606    }
2607
2608    /// Get the specified type iterator.
2609    #[inline]
2610    #[must_use]
2611    pub(crate) fn get_iter(&self, id: TypeId) -> Option<&FnIterator> {
2612        self.type_iterators.get(&id).map(|f| &**f)
2613    }
2614}
2615
2616/// Module containing all built-in [module resolvers][ModuleResolver].
2617#[cfg(not(feature = "no_module"))]
2618pub mod resolvers;
2619
2620#[cfg(not(feature = "no_module"))]
2621pub use resolvers::ModuleResolver;