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 += ¶ms.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;