Skip to main content

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