rhai/src/module/mod.rs

2340 lines
76 KiB
Rust
Raw Normal View History

//! Module defining external-loaded modules for Rhai.
2022-09-08 10:58:43 +08:00
#[cfg(feature = "metadata")]
2022-09-08 10:52:58 +08:00
use crate::api::type_names::format_type;
2022-01-29 11:09:43 +08:00
use crate::ast::FnAccess;
2022-11-04 21:47:09 +08:00
use crate::eval::Caches;
2021-11-13 22:36:23 +08:00
use crate::func::{
2021-11-16 12:26:37 +08:00
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
SendSync,
2021-11-13 22:36:23 +08:00
};
2022-09-08 17:49:37 +08:00
use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypesCollection};
2021-04-17 15:15:54 +08:00
use crate::{
2022-09-21 11:46:23 +08:00
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Identifier, ImmutableString,
NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec,
2021-04-17 15:15:54 +08:00
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
any::TypeId,
2022-09-15 08:55:07 +08:00
collections::BTreeMap,
2021-04-06 23:18:41 +08:00
fmt,
2022-01-29 11:09:43 +08:00
ops::{Add, AddAssign},
2020-11-16 23:10:14 +08:00
};
2022-08-22 22:28:27 +08:00
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
use crate::func::register::Mut;
2022-09-08 17:49:37 +08:00
use crate::func::StraightHashMap;
2020-11-17 12:23:53 +08:00
/// A type representing the namespace of a function.
2022-02-25 08:37:57 +08:00
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
2022-08-14 14:20:37 +08:00
#[cfg_attr(feature = "metadata", derive(serde::Serialize))]
#[cfg_attr(feature = "metadata", serde(rename_all = "camelCase"))]
2022-05-03 21:55:08 +08:00
#[non_exhaustive]
2020-11-17 12:23:53 +08:00
pub enum FnNamespace {
2020-12-26 13:05:57 +08:00
/// Module namespace only.
2022-01-29 11:09:43 +08:00
///
/// Ignored under `no_module`.
2020-11-17 12:23:53 +08:00
Internal,
2022-02-25 08:37:57 +08:00
/// Expose to global namespace.
Global,
2020-11-17 12:23:53 +08:00
}
2022-07-21 09:36:11 +08:00
impl FnNamespace {
/// Is this a module namespace?
#[inline(always)]
#[must_use]
2022-08-29 14:27:05 +08:00
pub const fn is_module_namespace(self) -> bool {
2022-07-21 09:36:11 +08:00
match self {
Self::Internal => true,
Self::Global => false,
}
}
/// Is this a global namespace?
#[inline(always)]
#[must_use]
2022-08-29 14:27:05 +08:00
pub const fn is_global_namespace(self) -> bool {
2022-07-21 09:36:11 +08:00
match self {
Self::Internal => false,
Self::Global => true,
}
}
}
2022-09-08 17:49:37 +08:00
/// A type containing a single registered function.
#[derive(Debug, Clone)]
2022-05-03 21:55:08 +08:00
#[non_exhaustive]
2022-09-08 17:49:37 +08:00
pub struct FuncInfo {
/// Function instance.
pub func: CallableFunction,
2020-11-17 12:23:53 +08:00
/// Function namespace.
pub namespace: FnNamespace,
2020-11-04 14:37:46 +08:00
/// Function access mode.
pub access: FnAccess,
/// Function name.
2022-10-29 14:59:20 +08:00
pub name: ImmutableString,
2020-11-04 14:37:46 +08:00
/// Number of parameters.
2022-09-08 17:49:37 +08:00
pub num_params: usize,
/// Parameter types (if applicable).
pub param_types: StaticVec<TypeId>,
/// Parameter names and types (if available).
#[cfg(feature = "metadata")]
2022-01-13 19:07:56 +08:00
pub params_info: StaticVec<Identifier>,
/// Return type name.
#[cfg(feature = "metadata")]
2022-01-13 19:07:56 +08:00
pub return_type: Identifier,
/// Comments.
#[cfg(feature = "metadata")]
2022-03-06 16:37:27 +08:00
pub comments: Box<[Box<str>]>,
2020-11-22 17:21:34 +08:00
}
impl FuncInfo {
2022-01-24 17:04:40 +08:00
/// _(metadata)_ Generate a signature of the function.
/// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-11-22 17:21:34 +08:00
pub fn gen_signature(&self) -> String {
2022-09-08 17:49:37 +08:00
let mut sig = format!("{}(", self.name);
2020-11-22 17:21:34 +08:00
2022-09-08 17:49:37 +08:00
let return_type = format_type(&self.return_type, true);
2022-01-13 22:51:10 +08:00
2022-09-08 17:49:37 +08:00
if self.params_info.is_empty() {
for x in 0..self.num_params {
2022-07-27 18:04:59 +08:00
sig.push('_');
2022-09-08 17:49:37 +08:00
if x < self.num_params - 1 {
2022-07-27 18:04:59 +08:00
sig.push_str(", ");
}
}
} else {
let params: StaticVec<_> = self
2022-01-13 19:07:56 +08:00
.params_info
.iter()
2022-01-17 21:51:04 +08:00
.map(|s| {
let mut seg = s.splitn(2, ':');
let name = match seg.next().unwrap().trim() {
"" => "_",
s => s,
};
let result: std::borrow::Cow<str> = match seg.next() {
2022-09-08 10:52:58 +08:00
Some(typ) => format!("{name}: {}", format_type(typ, false)).into(),
2022-01-17 21:51:04 +08:00
None => name.into(),
};
result
})
.collect();
2020-11-22 17:21:34 +08:00
sig.push_str(&params.join(", "));
}
2022-08-29 14:27:05 +08:00
sig.push(')');
2022-01-13 22:51:10 +08:00
if !self.func.is_script() && !return_type.is_empty() {
sig.push_str(" -> ");
sig.push_str(&return_type);
2020-11-22 17:21:34 +08:00
}
sig
}
2020-11-04 14:37:46 +08:00
}
2021-12-06 10:34:13 +08:00
/// _(internals)_ Calculate a non-zero [`u64`] hash key from a namespace-qualified function name and parameter types.
2021-03-08 15:30:32 +08:00
/// Exported under the `internals` feature only.
///
/// Module names are passed in via `&str` references from an iterator.
/// Parameter types are passed in via [`TypeId`] values from an iterator.
///
/// # Note
///
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
#[inline]
2022-01-04 15:22:48 +08:00
pub fn calc_native_fn_hash<'a>(
2022-09-06 14:16:15 +09:00
modules: impl IntoIterator<Item = &'a str, IntoIter = impl ExactSizeIterator<Item = &'a str>>,
2022-01-04 15:22:48 +08:00
fn_name: &str,
2021-03-08 15:30:32 +08:00
params: &[TypeId],
) -> u64 {
2022-09-21 11:46:23 +08:00
let hash_script = calc_fn_hash(modules, fn_name, params.len());
2022-07-27 18:04:59 +08:00
let hash_params = calc_fn_params_hash(params.iter().copied());
2021-03-08 15:30:32 +08:00
combine_hashes(hash_script, hash_params)
}
2020-11-10 23:26:50 +08:00
/// A module which may contain variables, sub-modules, external Rust functions,
/// and/or script-defined functions.
2020-11-15 12:07:35 +08:00
#[derive(Clone)]
2020-05-05 15:00:10 +08:00
pub struct Module {
2020-12-21 22:04:46 +08:00
/// ID identifying the module.
2022-10-29 14:12:18 +08:00
id: Option<ImmutableString>,
2022-07-25 17:42:15 +08:00
/// Module documentation.
#[cfg(feature = "metadata")]
doc: crate::SmartString,
2021-04-17 18:40:16 +08:00
/// Is this module internal?
pub(crate) internal: bool,
/// Is this module part of a standard library?
pub(crate) standard: bool,
/// Custom types.
2022-09-13 18:23:34 +08:00
custom_types: Option<CustomTypesCollection>,
2020-05-05 15:00:10 +08:00
/// Sub-modules.
2022-09-13 18:23:34 +08:00
modules: Option<BTreeMap<Identifier, Shared<Module>>>,
2021-01-02 23:30:10 +08:00
/// [`Module`] variables.
2022-09-13 18:23:34 +08:00
variables: Option<BTreeMap<Identifier, Dynamic>>,
2021-01-02 23:30:10 +08:00
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
2022-09-13 18:23:34 +08:00
all_variables: Option<StraightHashMap<Dynamic>>,
/// Functions (both native Rust and scripted).
functions: StraightHashMap<FuncInfo>,
/// Flattened collection of all functions, native Rust and scripted.
/// including those in sub-modules.
2022-09-13 18:23:34 +08:00
all_functions: Option<StraightHashMap<CallableFunction>>,
/// Bloom filter on native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters.
dynamic_functions_filter: BloomFilterU64,
2020-11-15 12:07:35 +08:00
/// Iterator functions, keyed by the type producing the iterator.
2022-09-13 18:23:34 +08:00
type_iterators: Option<BTreeMap<TypeId, Shared<IteratorFn>>>,
/// Flattened collection of iterator functions, including those in sub-modules.
2022-09-13 18:23:34 +08:00
all_type_iterators: Option<BTreeMap<TypeId, Shared<IteratorFn>>>,
2021-01-02 23:30:10 +08:00
/// Is the [`Module`] indexed?
indexed: bool,
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
contains_indexed_global_functions: bool,
2020-05-05 15:00:10 +08:00
}
2020-11-15 12:07:35 +08:00
impl Default for Module {
#[inline(always)]
2022-09-28 12:06:22 +08:00
#[must_use]
2020-11-15 12:07:35 +08:00
fn default() -> Self {
2021-05-18 12:24:11 +08:00
Self::new()
2020-11-15 12:07:35 +08:00
}
}
2020-05-05 15:00:10 +08:00
impl fmt::Debug for Module {
2022-09-27 08:52:39 +08:00
#[cold]
#[inline(never)]
2020-05-05 15:00:10 +08:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-04-06 23:18:41 +08:00
let mut d = f.debug_struct("Module");
2022-07-25 17:42:15 +08:00
d.field("id", &self.id)
.field(
2021-04-06 23:18:41 +08:00
"modules",
&self
.modules
2022-09-13 18:23:34 +08:00
.iter()
.flat_map(|m| m.keys())
2022-07-27 18:04:59 +08:00
.map(SmartString::as_str)
2022-09-15 08:55:07 +08:00
.collect::<Vec<_>>(),
2022-07-25 17:42:15 +08:00
)
.field("vars", &self.variables)
.field(
2021-04-06 23:18:41 +08:00
"functions",
&self
2021-12-06 11:12:54 +08:00
.iter_fn()
2021-04-20 19:19:35 +08:00
.map(|f| f.func.to_string())
2022-09-15 08:55:07 +08:00
.collect::<Vec<_>>(),
2021-04-06 23:18:41 +08:00
);
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
d.field("doc", &self.doc);
2021-04-06 23:18:41 +08:00
d.finish()
2020-05-05 15:00:10 +08:00
}
}
2021-01-11 23:09:33 +08:00
impl<M: AsRef<Module>> Add<M> for &Module {
type Output = Module;
#[inline]
2021-01-11 23:09:33 +08:00
fn add(self, rhs: M) -> Self::Output {
let mut module = self.clone();
module.merge(rhs.as_ref());
module
}
}
impl<M: AsRef<Module>> Add<M> for Module {
type Output = Self;
#[inline(always)]
2021-01-11 23:09:33 +08:00
fn add(mut self, rhs: M) -> Self::Output {
self.merge(rhs.as_ref());
self
}
}
impl<M: Into<Module>> AddAssign<M> for Module {
#[inline(always)]
2021-01-11 23:09:33 +08:00
fn add_assign(&mut self, rhs: M) {
self.combine(rhs.into());
}
}
impl Module {
2021-01-02 23:30:10 +08:00
/// Create a new [`Module`].
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_var("answer", 42_i64);
2021-08-26 23:58:41 +08:00
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ```
2022-09-13 21:12:44 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn new() -> Self {
2022-09-13 21:12:44 +08:00
Self::with_capacity(16)
2022-09-13 18:23:34 +08:00
}
/// Create a new [`Module`] with a pre-sized capacity for functions.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::with_capacity(10);
/// module.set_var("answer", 42_i64);
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ```
#[inline]
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
2022-10-29 14:12:18 +08:00
id: None,
2022-09-13 18:23:34 +08:00
#[cfg(feature = "metadata")]
doc: crate::SmartString::new_const(),
internal: false,
standard: false,
custom_types: None,
modules: None,
variables: None,
all_variables: None,
functions: StraightHashMap::with_capacity_and_hasher(capacity, Default::default()),
all_functions: None,
dynamic_functions_filter: BloomFilterU64::new(),
2022-09-13 18:23:34 +08:00
type_iterators: None,
all_type_iterators: None,
2021-05-18 12:24:11 +08:00
indexed: true,
contains_indexed_global_functions: false,
}
}
2021-01-02 23:30:10 +08:00
/// Get the ID of the [`Module`], if any.
2020-12-21 22:04:46 +08:00
///
/// # Example
///
/// ```
/// # use rhai::Module;
2020-12-21 22:04:46 +08:00
/// let mut module = Module::new();
/// module.set_id("hello");
2020-12-21 22:04:46 +08:00
/// assert_eq!(module.id(), Some("hello"));
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-12-21 22:04:46 +08:00
pub fn id(&self) -> Option<&str> {
2022-10-29 14:12:18 +08:00
self.id.as_ref().map(|s| s.as_str())
2020-12-21 22:04:46 +08:00
}
2021-03-29 11:36:02 +08:00
/// Get the ID of the [`Module`] as an [`Identifier`], if any.
2021-01-03 13:29:42 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2022-10-29 14:12:18 +08:00
pub(crate) const fn id_raw(&self) -> Option<&ImmutableString> {
self.id.as_ref()
2020-12-21 22:04:46 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set the ID of the [`Module`].
2020-12-21 22:04:46 +08:00
///
/// If the string is empty, it is equivalent to clearing the ID.
///
2020-12-21 22:04:46 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_id("hello");
/// assert_eq!(module.id(), Some("hello"));
/// ```
#[inline(always)]
2022-10-29 14:12:18 +08:00
pub fn set_id(&mut self, id: impl Into<ImmutableString>) -> &mut Self {
let id = id.into();
if id.is_empty() {
self.id = None;
} else {
self.id = Some(id);
}
self
}
2022-07-25 17:42:15 +08:00
/// Clear the ID of the [`Module`].
///
/// # Example
2020-12-21 22:04:46 +08:00
///
/// ```
/// # use rhai::Module;
2020-12-21 22:04:46 +08:00
/// let mut module = Module::new();
/// module.set_id("hello");
2020-12-21 22:04:46 +08:00
/// assert_eq!(module.id(), Some("hello"));
/// module.clear_id();
/// assert_eq!(module.id(), None);
2020-12-21 22:04:46 +08:00
/// ```
2021-01-03 13:29:42 +08:00
#[inline(always)]
pub fn clear_id(&mut self) -> &mut Self {
2022-10-29 14:12:18 +08:00
self.id = None;
2021-04-17 18:40:16 +08:00
self
}
2022-07-25 17:42:15 +08:00
/// Get the documentation of the [`Module`], if any.
/// Exported under the `metadata` feature only.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_doc("//! This is my special module.");
/// assert_eq!(module.doc(), "//! This is my special module.");
/// ```
#[cfg(feature = "metadata")]
#[inline]
#[must_use]
pub fn doc(&self) -> &str {
&self.doc
}
/// Set the documentation of the [`Module`].
/// Exported under the `metadata` feature only.
///
/// If the string is empty, it is equivalent to clearing the documentation.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_doc("//! This is my special module.");
/// assert_eq!(module.doc(), "//! This is my special module.");
/// ```
#[cfg(feature = "metadata")]
#[inline(always)]
pub fn set_doc(&mut self, doc: impl Into<crate::SmartString>) -> &mut Self {
self.doc = doc.into();
self
}
/// Clear the documentation of the [`Module`].
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_doc("//! This is my special module.");
/// assert_eq!(module.doc(), "//! This is my special module.");
2022-07-26 17:19:41 +08:00
/// module.clear_doc();
2022-07-25 17:42:15 +08:00
/// assert_eq!(module.doc(), "");
/// ```
#[cfg(feature = "metadata")]
#[inline(always)]
pub fn clear_doc(&mut self) -> &mut Self {
self.doc.clear();
self
}
/// Clear the [`Module`].
#[inline(always)]
pub fn clear(&mut self) {
2022-10-29 14:12:18 +08:00
self.id = None;
2022-07-26 16:49:05 +08:00
#[cfg(feature = "metadata")]
2022-07-25 17:42:15 +08:00
self.doc.clear();
self.internal = false;
self.standard = false;
2022-09-13 18:23:34 +08:00
self.custom_types = None;
self.modules = None;
self.variables = None;
self.all_variables = None;
self.functions.clear();
2022-09-13 18:23:34 +08:00
self.all_functions = None;
self.dynamic_functions_filter.clear();
2022-09-13 18:23:34 +08:00
self.type_iterators = None;
self.all_type_iterators = None;
self.indexed = false;
self.contains_indexed_global_functions = false;
}
/// Map a custom type to a friendly display name.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// #[derive(Clone)]
2022-04-06 17:25:04 +08:00
/// struct TestStruct;
///
2022-04-06 17:25:04 +08:00
/// let name = std::any::type_name::<TestStruct>();
///
/// let mut module = Module::new();
///
2022-04-06 17:25:04 +08:00
/// module.set_custom_type::<TestStruct>("MyType");
///
2022-04-06 17:25:04 +08:00
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
/// ```
#[inline(always)]
pub fn set_custom_type<T>(&mut self, name: &str) -> &mut Self {
2022-09-13 18:23:34 +08:00
self.custom_types
2022-09-13 21:12:44 +08:00
.get_or_insert_with(CustomTypesCollection::new)
2022-09-13 18:23:34 +08:00
.add_type::<T>(name);
self
}
2022-03-29 08:18:20 +08:00
/// Map a custom type to a friendly display name.
///
/// ```
/// # use rhai::Module;
/// #[derive(Clone)]
2022-04-06 17:25:04 +08:00
/// struct TestStruct;
///
2022-04-06 17:25:04 +08:00
/// let name = std::any::type_name::<TestStruct>();
///
/// let mut module = Module::new();
///
/// module.set_custom_type_raw(name, "MyType");
///
2022-04-06 17:25:04 +08:00
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
/// ```
2022-03-29 08:18:20 +08:00
#[inline(always)]
pub fn set_custom_type_raw(
&mut self,
type_path: impl Into<Identifier>,
2022-03-29 08:18:20 +08:00
name: impl Into<Identifier>,
) -> &mut Self {
2022-09-13 18:23:34 +08:00
self.custom_types
2022-09-13 21:12:44 +08:00
.get_or_insert_with(CustomTypesCollection::new)
.add(type_path, name);
self
2022-03-29 08:18:20 +08:00
}
/// Get the display name of a registered custom type.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// #[derive(Clone)]
2022-04-06 17:25:04 +08:00
/// struct TestStruct;
///
2022-04-06 17:25:04 +08:00
/// let name = std::any::type_name::<TestStruct>();
///
/// let mut module = Module::new();
///
2022-04-06 17:25:04 +08:00
/// module.set_custom_type::<TestStruct>("MyType");
///
2022-04-06 17:25:04 +08:00
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
/// ```
#[inline]
2022-07-27 18:04:59 +08:00
#[must_use]
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
2022-09-13 18:23:34 +08:00
self.custom_types
.as_ref()
.and_then(|c| c.get(key))
.map(|t| t.display_name.as_str())
}
2022-08-14 14:39:30 +08:00
/// Returns `true` if this [`Module`] contains no items.
2020-09-30 09:57:21 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
2020-09-30 09:57:21 +08:00
///
/// ```
/// # use rhai::Module;
2020-09-30 09:57:21 +08:00
/// let module = Module::new();
/// assert!(module.is_empty());
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-09-30 09:57:21 +08:00
pub fn is_empty(&self) -> bool {
2021-11-27 14:24:36 +08:00
self.indexed
&& !self.contains_indexed_global_functions
&& self.functions.is_empty()
2022-09-13 18:23:34 +08:00
&& self.all_functions.as_ref().map_or(true, |m| m.is_empty())
&& self.variables.as_ref().map_or(true, |m| m.is_empty())
&& self.all_variables.as_ref().map_or(true, |m| m.is_empty())
&& self.modules.as_ref().map_or(true, |m| m.is_empty())
&& self.type_iterators.as_ref().map_or(true, |t| t.is_empty())
&& self
.all_type_iterators
.as_ref()
.map_or(true, |m| m.is_empty())
2020-09-30 09:57:21 +08:00
}
2021-01-02 23:30:10 +08:00
/// Is the [`Module`] indexed?
///
2021-04-19 15:41:24 +08:00
/// A module must be indexed before it can be used in an `import` statement.
///
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
2021-04-19 15:41:24 +08:00
/// assert!(module.is_indexed());
///
/// module.set_native_fn("foo", |x: &mut i64, y: i64| { *x = y; Ok(()) });
/// assert!(!module.is_indexed());
///
2020-11-08 16:49:59 +08:00
/// # #[cfg(not(feature = "no_module"))]
/// # {
/// module.build_index();
/// assert!(module.is_indexed());
2020-11-08 16:49:59 +08:00
/// # }
/// ```
2021-01-03 13:29:42 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-06-28 18:06:05 +08:00
pub const fn is_indexed(&self) -> bool {
self.indexed
}
2022-01-24 17:04:40 +08:00
/// _(metadata)_ Generate signatures for all the non-private functions in the [`Module`].
/// Exported under the `metadata` feature only.
#[cfg(feature = "metadata")]
#[inline]
2021-02-09 14:22:55 +08:00
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
2021-12-06 11:12:54 +08:00
self.iter_fn()
2022-09-08 17:49:37 +08:00
.filter(|&f| match f.access {
FnAccess::Public => true,
FnAccess::Private => false,
})
2022-07-27 18:04:59 +08:00
.map(FuncInfo::gen_signature)
2020-11-22 17:21:34 +08:00
}
2021-01-02 23:30:10 +08:00
/// Does a variable exist in the [`Module`]?
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_var("answer", 42_i64);
/// assert!(module.contains_var("answer"));
/// ```
2020-10-08 22:25:50 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-05 17:51:40 +08:00
pub fn contains_var(&self, name: &str) -> bool {
2022-09-13 18:23:34 +08:00
self.variables
.as_ref()
.map_or(false, |m| m.contains_key(name))
}
2021-01-02 23:30:10 +08:00
/// Get the value of a [`Module`] variable.
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_var("answer", 42_i64);
2021-08-26 23:58:41 +08:00
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-05 17:51:40 +08:00
pub fn get_var_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
self.get_var(name).and_then(Dynamic::try_cast::<T>)
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Get a [`Module`] variable as a [`Dynamic`].
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_var("answer", 42_i64);
2021-08-26 23:58:41 +08:00
/// assert_eq!(module.get_var("answer").expect("answer should exist").cast::<i64>(), 42);
/// ```
2020-10-08 22:25:50 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-05 17:51:40 +08:00
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
2022-09-13 18:23:34 +08:00
self.variables.as_ref().and_then(|m| m.get(name)).cloned()
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a variable into the [`Module`].
2020-05-05 15:00:10 +08:00
///
/// If there is an existing variable of the same name, it is replaced.
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// module.set_var("answer", 42_i64);
2021-08-26 23:58:41 +08:00
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// ```
#[inline]
2020-12-11 12:57:07 +08:00
pub fn set_var(
&mut self,
2021-03-29 11:36:02 +08:00
name: impl Into<Identifier>,
2020-12-11 12:57:07 +08:00
value: impl Variant + Clone,
) -> &mut Self {
2021-04-17 22:19:48 +08:00
let ident = name.into();
let value = Dynamic::from(value);
if self.indexed {
2022-09-21 11:46:23 +08:00
let hash_var = crate::calc_var_hash(Some(""), &ident);
2022-09-13 18:23:34 +08:00
self.all_variables
.get_or_insert_with(|| Default::default())
.insert(hash_var, value.clone());
2021-04-17 22:19:48 +08:00
}
2022-09-13 18:23:34 +08:00
self.variables
.get_or_insert_with(|| Default::default())
.insert(ident, value);
2020-07-12 11:46:53 +08:00
self
2020-05-05 15:00:10 +08:00
}
2022-03-03 13:02:57 +08:00
/// Get a namespace-qualified [`Module`] variable as a [`Dynamic`].
2021-10-29 17:01:29 +08:00
#[cfg(not(feature = "no_module"))]
#[inline]
2022-03-03 13:02:57 +08:00
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option<Dynamic> {
2022-09-13 18:23:34 +08:00
self.all_variables
.as_ref()
.and_then(|c| c.get(&hash_var).cloned())
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a script-defined function into the [`Module`].
///
/// If there is an existing function of the same name and number of arguments, it is replaced.
2020-09-24 23:32:54 +08:00
#[cfg(not(feature = "no_function"))]
2020-10-08 22:25:50 +08:00
#[inline]
pub fn set_script_fn(&mut self, fn_def: impl Into<Shared<crate::ast::ScriptFnDef>>) -> u64 {
2020-11-25 09:36:06 +08:00
let fn_def = fn_def.into();
// None + function name + number of arguments.
2020-09-24 22:50:28 +08:00
let num_params = fn_def.params.len();
2022-09-21 11:46:23 +08:00
let hash_script = crate::calc_fn_hash(None, &fn_def.name, num_params);
#[cfg(feature = "metadata")]
2022-08-13 18:07:42 +08:00
let params_info = fn_def.params.iter().map(Into::into).collect();
self.functions.insert(
2020-06-11 18:13:33 +08:00
hash_script,
2021-06-29 18:25:20 +08:00
FuncInfo {
2022-09-08 17:49:37 +08:00
name: fn_def.name.as_str().into(),
namespace: FnNamespace::Internal,
access: fn_def.access,
num_params,
2022-01-13 19:07:56 +08:00
param_types: StaticVec::new_const(),
2022-09-08 17:49:37 +08:00
#[cfg(feature = "metadata")]
params_info,
#[cfg(feature = "metadata")]
return_type: "".into(),
#[cfg(feature = "metadata")]
comments: Box::default(),
func: fn_def.into(),
2022-09-15 08:55:07 +08:00
},
);
self.indexed = false;
self.contains_indexed_global_functions = false;
2020-09-24 22:50:28 +08:00
hash_script
}
2021-03-12 14:11:08 +08:00
/// Get a shared reference to the script-defined function in the [`Module`] based on name
/// and number of parameters.
2020-10-05 12:09:45 +08:00
#[cfg(not(feature = "no_function"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn get_script_fn(
&self,
2021-11-27 23:04:45 +08:00
name: impl AsRef<str>,
num_params: usize,
2021-03-12 14:11:08 +08:00
) -> Option<&Shared<crate::ast::ScriptFnDef>> {
2022-07-27 18:04:59 +08:00
if self.functions.is_empty() {
None
} else {
2021-11-27 23:04:45 +08:00
let name = name.as_ref();
2021-12-06 11:12:54 +08:00
self.iter_fn()
2022-09-08 17:49:37 +08:00
.find(|f| f.num_params == num_params && f.name == name)
2021-11-27 14:24:36 +08:00
.and_then(|f| f.func.get_script_fn_def())
}
}
2022-09-13 18:23:34 +08:00
/// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules,
/// creating one if empty.
2020-12-26 23:21:16 +08:00
///
2021-01-02 23:30:10 +08:00
/// # WARNING
2020-12-26 23:21:16 +08:00
///
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
2021-01-02 23:30:10 +08:00
/// Thus the [`Module`] is automatically set to be non-indexed.
2020-12-28 09:49:54 +08:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2022-09-15 08:55:07 +08:00
pub(crate) fn get_sub_modules_mut(&mut self) -> &mut BTreeMap<Identifier, Shared<Module>> {
2020-12-26 13:05:57 +08:00
// We must assume that the user has changed the sub-modules
// (otherwise why take a mutable reference?)
2022-09-13 18:23:34 +08:00
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
2020-12-26 13:05:57 +08:00
self.indexed = false;
self.contains_indexed_global_functions = false;
2020-12-26 13:05:57 +08:00
2022-09-13 18:23:34 +08:00
self.modules.get_or_insert_with(|| Default::default())
2020-12-26 13:05:57 +08:00
}
2021-01-02 23:30:10 +08:00
/// Does a sub-module exist in the [`Module`]?
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// let sub_module = Module::new();
/// module.set_sub_module("question", sub_module);
/// assert!(module.contains_sub_module("question"));
/// ```
2020-10-08 22:25:50 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-05 15:00:10 +08:00
pub fn contains_sub_module(&self, name: &str) -> bool {
2022-09-13 18:23:34 +08:00
self.modules
.as_ref()
.map_or(false, |m| m.contains_key(name))
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Get a sub-module in the [`Module`].
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// let sub_module = Module::new();
/// module.set_sub_module("question", sub_module);
/// assert!(module.get_sub_module("question").is_some());
/// ```
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-05 15:00:10 +08:00
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
2022-09-13 18:23:34 +08:00
self.modules
.as_ref()
.and_then(|m| m.get(name))
.map(|m| &**m)
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a sub-module into the [`Module`].
2020-05-05 15:00:10 +08:00
///
/// If there is an existing sub-module of the same name, it is replaced.
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// let sub_module = Module::new();
/// module.set_sub_module("question", sub_module);
/// assert!(module.get_sub_module("question").is_some());
/// ```
#[inline]
2020-11-09 22:44:20 +08:00
pub fn set_sub_module(
&mut self,
2021-03-29 11:36:02 +08:00
name: impl Into<Identifier>,
2020-11-09 22:44:20 +08:00
sub_module: impl Into<Shared<Module>>,
) -> &mut Self {
2022-09-13 18:23:34 +08:00
self.modules
.get_or_insert_with(|| Default::default())
.insert(name.into(), sub_module.into());
self.indexed = false;
self.contains_indexed_global_functions = false;
2020-07-12 11:46:53 +08:00
self
2020-05-05 15:00:10 +08:00
}
2021-01-02 23:30:10 +08:00
/// Does the particular Rust function exist in the [`Module`]?
2020-05-05 17:51:40 +08:00
///
2021-03-15 12:39:06 +08:00
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
2021-03-15 12:39:06 +08:00
/// let hash = module.set_native_fn("calc", || Ok(42_i64));
2021-03-17 09:58:08 +08:00
/// assert!(module.contains_fn(hash));
/// ```
2021-03-04 18:13:47 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-03-17 09:58:08 +08:00
pub fn contains_fn(&self, hash_fn: u64) -> bool {
2022-07-27 18:04:59 +08:00
if self.functions.is_empty() {
2022-03-03 13:02:57 +08:00
false
2022-07-27 18:04:59 +08:00
} else {
self.functions.contains_key(&hash_fn)
2022-03-03 13:02:57 +08:00
}
2020-05-05 17:51:40 +08:00
}
2021-12-21 22:16:03 +08:00
/// _(metadata)_ Update the metadata (parameter names/types and return type) of a registered function.
/// Exported under the `metadata` feature only.
2020-11-22 17:21:34 +08:00
///
2021-03-15 12:39:06 +08:00
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
2021-01-02 23:30:10 +08:00
///
/// ## Parameter Names and Types
2020-11-22 22:15:17 +08:00
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
2021-01-02 23:30:10 +08:00
/// ## Return Type
///
/// The _last entry_ in the list should be the _return type_ of the function.
2020-11-22 22:15:17 +08:00
/// In other words, the number of entries should be one larger than the number of parameters.
#[cfg(feature = "metadata")]
#[inline]
2022-01-04 15:22:48 +08:00
pub fn update_fn_metadata<S: AsRef<str>>(
&mut self,
hash_fn: u64,
arg_names: impl AsRef<[S]>,
) -> &mut Self {
let mut param_names: StaticVec<_> = arg_names
2022-01-04 15:22:48 +08:00
.as_ref()
2021-03-24 09:56:25 +08:00
.iter()
.map(|s| s.as_ref().into())
2021-03-24 09:56:25 +08:00
.collect();
2021-07-26 22:22:27 +08:00
if let Some(f) = self.functions.get_mut(&hash_fn) {
2022-09-08 17:49:37 +08:00
let (param_names, return_type_name) = if param_names.len() > f.num_params {
2022-01-06 11:07:52 +08:00
let return_type = param_names.pop().unwrap();
(param_names, return_type)
} else {
(param_names, crate::SmartString::new_const())
};
2022-09-08 17:49:37 +08:00
f.params_info = param_names;
f.return_type = return_type_name;
2021-07-26 22:22:27 +08:00
}
2021-05-25 10:54:48 +08:00
2020-11-22 17:21:34 +08:00
self
}
2022-01-24 17:04:40 +08:00
/// _(metadata)_ Update the metadata (parameter names/types, return type and doc-comments) of a registered function.
2021-12-21 22:16:03 +08:00
/// Exported under the `metadata` feature only.
///
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
///
/// ## Parameter Names and Types
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
/// ## Return Type
///
/// The _last entry_ in the list should be the _return type_ of the function. In other words,
/// the number of entries should be one larger than the number of parameters.
///
/// ## Comments
///
/// Block doc-comments should be kept in a single line.
///
/// Line doc-comments should be kept in one string slice per line without the termination line-break.
///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`.
#[cfg(feature = "metadata")]
#[inline]
2022-01-04 15:22:48 +08:00
pub fn update_fn_metadata_with_comments<A: AsRef<str>, C: AsRef<str>>(
2021-12-21 22:16:03 +08:00
&mut self,
hash_fn: u64,
2022-01-04 15:22:48 +08:00
arg_names: impl AsRef<[A]>,
comments: impl AsRef<[C]>,
2021-12-21 22:16:03 +08:00
) -> &mut Self {
self.update_fn_metadata(hash_fn, arg_names);
2022-01-04 22:16:20 +08:00
let comments = comments.as_ref();
if !comments.is_empty() {
2022-01-06 11:07:52 +08:00
let f = self.functions.get_mut(&hash_fn).unwrap();
2022-09-08 17:49:37 +08:00
f.comments = comments.iter().map(|s| s.as_ref().into()).collect();
2021-12-21 22:16:03 +08:00
}
self
}
2020-12-07 21:54:52 +08:00
/// Update the namespace of a registered function.
///
2021-03-15 12:39:06 +08:00
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
#[inline]
2021-03-08 15:30:32 +08:00
pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self {
2020-12-07 21:54:52 +08:00
if let Some(f) = self.functions.get_mut(&hash_fn) {
2022-09-08 17:49:37 +08:00
f.namespace = namespace;
2021-03-24 09:56:25 +08:00
self.indexed = false;
self.contains_indexed_global_functions = false;
2020-12-07 21:54:52 +08:00
}
self
}
/// Remap type ID.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
fn map_type(map: bool, type_id: TypeId) -> TypeId {
if !map {
return type_id;
}
if type_id == TypeId::of::<&str>() {
// Map &str to ImmutableString
return TypeId::of::<ImmutableString>();
}
if type_id == TypeId::of::<String>() {
// Map String to ImmutableString
return TypeId::of::<ImmutableString>();
}
type_id
}
2021-12-06 10:34:13 +08:00
/// Set a Rust function into the [`Module`], returning a non-zero hash key.
2020-05-05 17:51:40 +08:00
///
/// If there is an existing Rust function of the same hash, it is replaced.
2020-07-11 15:09:17 +08:00
///
2021-01-02 23:30:10 +08:00
/// # WARNING - Low Level API
2020-07-11 15:09:17 +08:00
///
/// This function is very low level.
///
/// ## Parameter Names and Types
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
/// ## Return Type
///
/// The _last entry_ in the list should be the _return type_ of the function.
/// In other words, the number of entries should be one larger than the number of parameters.
2021-01-03 13:29:42 +08:00
#[inline]
2020-07-11 15:09:17 +08:00
pub fn set_fn(
2020-05-22 21:50:24 +08:00
&mut self,
2022-01-04 15:22:48 +08:00
name: impl AsRef<str>,
2020-11-17 12:23:53 +08:00
namespace: FnNamespace,
2020-05-22 21:50:24 +08:00
access: FnAccess,
2021-11-27 23:04:45 +08:00
arg_names: Option<&[&str]>,
2022-01-04 15:22:48 +08:00
arg_types: impl AsRef<[TypeId]>,
func: CallableFunction,
2021-03-08 15:30:32 +08:00
) -> u64 {
2021-11-27 23:04:45 +08:00
let _arg_names = arg_names;
2021-03-08 15:30:32 +08:00
let is_method = func.is_method();
2020-09-11 22:32:59 +08:00
2021-05-05 18:38:52 +08:00
let mut param_types: StaticVec<_> = arg_types
2022-01-04 15:22:48 +08:00
.as_ref()
2021-03-08 15:30:32 +08:00
.iter()
2022-07-27 18:04:59 +08:00
.copied()
2021-03-08 15:30:32 +08:00
.enumerate()
.map(|(i, type_id)| Self::map_type(!is_method || i > 0, type_id))
.collect();
2021-05-05 18:38:52 +08:00
param_types.shrink_to_fit();
let is_dynamic = param_types
.iter()
.any(|&type_id| type_id == TypeId::of::<Dynamic>());
#[cfg(feature = "metadata")]
let (param_names, return_type_name) = {
let mut names = _arg_names
.iter()
.flat_map(|&p| p.iter())
.map(|&s| s.into())
.collect::<StaticVec<_>>();
2022-01-04 15:22:48 +08:00
let return_type = if names.len() > arg_types.as_ref().len() {
2022-01-06 11:07:52 +08:00
names.pop().unwrap()
} else {
crate::SmartString::new_const()
};
names.shrink_to_fit();
(names, return_type)
};
2020-05-17 22:19:49 +08:00
2022-07-05 16:26:38 +08:00
let name = name.as_ref();
2022-09-21 11:46:23 +08:00
let hash_script = calc_fn_hash(None, name, param_types.len());
let hash_params = calc_fn_params_hash(param_types.iter().copied());
let hash_fn = combine_hashes(hash_script, hash_params);
2021-03-08 15:30:32 +08:00
if is_dynamic {
self.dynamic_functions_filter.mark(hash_script);
}
self.functions.insert(
hash_fn,
2021-06-29 18:25:20 +08:00
FuncInfo {
2022-07-20 21:28:17 +09:00
func,
2022-09-08 17:49:37 +08:00
name: name.into(),
namespace,
access,
num_params: param_types.len(),
2022-01-13 19:07:56 +08:00
param_types,
2022-09-08 17:49:37 +08:00
#[cfg(feature = "metadata")]
params_info: param_names,
#[cfg(feature = "metadata")]
return_type: return_type_name,
#[cfg(feature = "metadata")]
comments: Box::default(),
2022-09-15 08:55:07 +08:00
},
);
self.indexed = false;
self.contains_indexed_global_functions = false;
hash_fn
}
/// _(metadata)_ Set a Rust function into the [`Module`], returning a non-zero hash key.
/// Exported under the `metadata` feature only.
///
/// If there is an existing Rust function of the same hash, it is replaced.
///
/// # WARNING - Low Level API
///
/// This function is very low level.
///
/// ## Parameter Names and Types
///
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
///
/// ## Return Type
///
/// The _last entry_ in the list should be the _return type_ of the function.
/// In other words, the number of entries should be one larger than the number of parameters.
2021-12-21 22:16:03 +08:00
///
/// ## Comments
///
/// Block doc-comments should be kept in a single line.
///
/// Line doc-comments should be kept in one string slice per line without the termination line-break.
///
/// Leading white-spaces should be stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`.
#[cfg(feature = "metadata")]
#[inline]
2022-01-04 15:22:48 +08:00
pub fn set_fn_with_comments<S: AsRef<str>>(
&mut self,
2022-01-04 15:22:48 +08:00
name: impl AsRef<str>,
namespace: FnNamespace,
access: FnAccess,
arg_names: Option<&[&str]>,
2022-01-04 15:22:48 +08:00
arg_types: impl AsRef<[TypeId]>,
comments: impl AsRef<[S]>,
func: CallableFunction,
) -> u64 {
let hash = self.set_fn(name, namespace, access, arg_names, arg_types, func);
2022-01-04 22:16:20 +08:00
let comments = comments.as_ref();
if !comments.is_empty() {
2022-01-06 11:07:52 +08:00
let f = self.functions.get_mut(&hash).unwrap();
2022-09-08 17:49:37 +08:00
f.comments = comments.iter().map(|s| s.as_ref().into()).collect();
}
hash
}
2020-11-20 16:52:28 +08:00
/// Set a Rust function taking a reference to the scripting [`Engine`][crate::Engine],
2020-12-26 23:21:16 +08:00
/// the current set of functions, plus a list of mutable [`Dynamic`] references
2021-12-06 10:34:13 +08:00
/// into the [`Module`], returning a non-zero hash key.
///
/// Use this to register a built-in function which must reference settings on the scripting
2020-11-20 16:52:28 +08:00
/// [`Engine`][crate::Engine] (e.g. to prevent growing an array beyond the allowed maximum size),
/// or to call a script-defined function in the current evaluation context.
///
/// If there is a similar existing Rust function, it is replaced.
2020-07-07 22:59:23 +08:00
///
2021-01-02 23:30:10 +08:00
/// # WARNING - Low Level API
2020-07-07 22:59:23 +08:00
///
/// This function is very low level.
///
2021-12-27 11:43:11 +08:00
/// # Arguments
///
2020-11-20 16:52:28 +08:00
/// A list of [`TypeId`]'s is taken as the argument types.
2020-07-07 22:59:23 +08:00
///
2021-01-02 23:30:10 +08:00
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][Dynamic],
2020-07-07 22:59:23 +08:00
/// which is guaranteed to contain enough arguments of the correct types.
///
2020-10-03 16:25:58 +08:00
/// The function is assumed to be a _method_, meaning that the first argument should not be consumed.
/// All other arguments can be consumed.
///
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
2020-07-07 22:59:23 +08:00
///
/// To access an argument value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`.
2020-07-07 22:59:23 +08:00
/// Notice that this will _consume_ the argument, replacing it with `()`.
///
/// To access the first mutable argument, use `args.get_mut(0).unwrap()`
2020-07-07 22:59:23 +08:00
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered. Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
2020-07-07 22:59:23 +08:00
///
/// ```
2020-11-17 12:23:53 +08:00
/// use rhai::{Module, FnNamespace, FnAccess};
2020-07-07 22:59:23 +08:00
///
/// let mut module = Module::new();
/// let hash = module.set_raw_fn("double_or_not", FnNamespace::Internal, FnAccess::Public,
2020-07-07 22:59:23 +08:00
/// // Pass parameter types via a slice with TypeId's
2020-07-28 10:25:57 +08:00
/// &[std::any::TypeId::of::<i64>(), std::any::TypeId::of::<bool>()],
2020-07-07 22:59:23 +08:00
/// // Fixed closure signature
2020-10-18 17:08:57 +08:00
/// |context, args| {
2020-07-07 22:59:23 +08:00
/// // 'args' is guaranteed to be the right length and of the correct types
///
/// // Get the second parameter by 'consuming' it
/// let double = std::mem::take(args[1]).cast::<bool>();
/// // Since it is a primary type, it can also be cheaply copied
2021-03-30 18:57:16 +08:00
/// let double = args[1].clone_cast::<bool>();
2020-07-07 22:59:23 +08:00
/// // Get a mutable reference to the first argument.
/// let mut x = args[0].write_lock::<i64>().unwrap();
2020-07-07 22:59:23 +08:00
///
/// let orig = *x;
///
/// if double {
/// *x *= 2; // the first argument can be mutated
/// }
///
2021-12-25 23:49:14 +08:00
/// Ok(orig) // return RhaiResult<T>
2020-07-07 22:59:23 +08:00
/// });
///
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
2020-07-07 22:59:23 +08:00
/// ```
2021-01-03 13:29:42 +08:00
#[inline(always)]
2022-08-24 18:27:58 +08:00
pub fn set_raw_fn<T: Variant + Clone>(
&mut self,
2022-01-04 15:22:48 +08:00
name: impl AsRef<str>,
2020-11-17 12:23:53 +08:00
namespace: FnNamespace,
access: FnAccess,
2022-01-04 15:22:48 +08:00
arg_types: impl AsRef<[TypeId]>,
2022-08-24 18:27:58 +08:00
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf<T> + SendSync + 'static,
) -> u64 {
2020-11-02 11:04:45 +08:00
let f =
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
2020-11-17 12:23:53 +08:00
self.set_fn(
name,
2020-11-17 12:23:53 +08:00
namespace,
access,
2020-11-22 17:21:34 +08:00
None,
arg_types,
2022-09-06 14:51:32 +09:00
CallableFunction::Method(Shared::new(f)),
)
}
2021-12-06 10:34:13 +08:00
/// Set a Rust function into the [`Module`], returning a non-zero hash key.
2020-05-05 17:51:40 +08:00
///
/// If there is a similar existing Rust function, it is replaced.
///
2021-03-15 12:39:06 +08:00
/// # Function Namespace
2020-11-22 22:15:17 +08:00
///
2021-03-15 12:39:06 +08:00
/// The default function namespace is [`FnNamespace::Internal`].
/// Use [`update_fn_namespace`][Module::update_fn_namespace] to change it.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-03-15 12:39:06 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
2021-03-15 12:39:06 +08:00
/// let hash = module.set_native_fn("calc", || Ok(42_i64));
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
/// ```
2021-01-03 13:29:42 +08:00
#[inline(always)]
2022-08-24 18:27:58 +08:00
pub fn set_native_fn<A, T, F, S>(
&mut self,
name: impl AsRef<str> + Into<Identifier>,
func: F,
) -> u64
2021-03-15 12:39:06 +08:00
where
T: Variant + Clone,
2022-08-24 18:27:58 +08:00
F: RegisterNativeFunction<A, T, RhaiResultOf<S>>,
2021-03-15 12:39:06 +08:00
{
self.set_fn(
name,
2020-11-17 12:23:53 +08:00
FnNamespace::Internal,
2020-10-01 23:31:27 +08:00
FnAccess::Public,
2020-11-22 17:21:34 +08:00
None,
2021-03-15 12:39:06 +08:00
&F::param_types(),
func.into_callable_function(),
)
2020-05-05 17:51:40 +08:00
}
2021-12-06 10:34:13 +08:00
/// Set a Rust getter function taking one mutable parameter, returning a non-zero hash key.
/// This function is automatically exposed to the global namespace.
///
/// If there is a similar existing Rust getter function, it is replaced.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # use rhai::Module;
/// let mut module = Module::new();
/// let hash = module.set_getter_fn("value", |x: &mut i64| { Ok(*x) });
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
/// ```
#[cfg(not(feature = "no_object"))]
2021-01-03 13:29:42 +08:00
#[inline(always)]
pub fn set_getter_fn<A, T, F, S>(&mut self, name: impl AsRef<str>, func: F) -> u64
2021-03-15 12:39:06 +08:00
where
A: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>,), T, RhaiResultOf<S>> + SendSync + 'static,
2021-03-15 12:39:06 +08:00
{
self.set_fn(
2022-01-04 15:22:48 +08:00
crate::engine::make_getter(name.as_ref()).as_str(),
FnNamespace::Global,
2020-10-01 23:31:27 +08:00
FnAccess::Public,
2020-11-22 17:21:34 +08:00
None,
2021-03-15 12:39:06 +08:00
&F::param_types(),
func.into_callable_function(),
)
2020-05-05 17:51:40 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`],
2021-12-06 10:34:13 +08:00
/// returning a non-zero hash key.
/// This function is automatically exposed to the global namespace.
///
/// If there is a similar existing setter Rust function, it is replaced.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_setter_fn("value", |x: &mut i64, y: ImmutableString| {
/// *x = y.len() as i64;
/// Ok(())
/// });
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
/// ```
#[cfg(not(feature = "no_object"))]
2021-01-03 13:29:42 +08:00
#[inline(always)]
2022-08-22 00:15:00 +08:00
pub fn set_setter_fn<A, T, F, S>(&mut self, name: impl AsRef<str>, func: F) -> u64
2021-03-15 12:39:06 +08:00
where
A: Variant + Clone,
2022-08-22 00:15:00 +08:00
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>, T), (), RhaiResultOf<S>> + SendSync + 'static,
2021-03-15 12:39:06 +08:00
{
self.set_fn(
2022-01-04 15:22:48 +08:00
crate::engine::make_setter(name.as_ref()).as_str(),
FnNamespace::Global,
2021-03-15 12:39:06 +08:00
FnAccess::Public,
None,
&F::param_types(),
func.into_callable_function(),
)
}
2022-08-22 00:15:00 +08:00
/// Set a pair of Rust getter and setter functions into the [`Module`], returning both non-zero hash keys.
/// This is a short-hand for [`set_getter_fn`][Module::set_getter_fn] and [`set_setter_fn`][Module::set_setter_fn].
///
/// These function are automatically exposed to the global namespace.
///
/// If there are similar existing Rust functions, they are replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let (hash_get, hash_set) = module.set_getter_setter_fn("value",
/// |x: &mut i64| { Ok(x.to_string().into()) },
/// |x: &mut i64, y: ImmutableString| {
/// *x = y.len() as i64;
/// Ok(())
/// }
/// );
/// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set));
/// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn set_getter_setter_fn<A: Variant + Clone, T: Variant + Clone, S1, S2>(
&mut self,
name: impl AsRef<str>,
getter: impl RegisterNativeFunction<(Mut<A>,), T, RhaiResultOf<S1>> + SendSync + 'static,
setter: impl RegisterNativeFunction<(Mut<A>, T), (), RhaiResultOf<S2>> + SendSync + 'static,
) -> (u64, u64) {
(
self.set_getter_fn(name.as_ref(), getter),
self.set_setter_fn(name.as_ref(), setter),
)
}
2021-01-02 23:30:10 +08:00
/// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`],
2021-12-06 10:34:13 +08:00
/// returning a non-zero hash key.
/// This function is automatically exposed to the global namespace.
///
/// If there is a similar existing setter Rust function, it is replaced.
///
/// # Panics
///
2021-12-06 20:52:47 +08:00
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
/// Indexers for arrays, object maps and strings cannot be registered.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
2020-06-06 13:06:00 +08:00
/// let hash = module.set_indexer_get_fn(|x: &mut i64, y: ImmutableString| {
/// Ok(*x + y.len() as i64)
/// });
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
/// ```
2021-05-18 20:12:30 +08:00
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline]
pub fn set_indexer_get_fn<A, B, T, F, S>(&mut self, func: F) -> u64
2021-03-15 12:39:06 +08:00
where
A: Variant + Clone,
B: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S>> + SendSync + 'static,
2021-03-15 12:39:06 +08:00
{
2021-05-18 20:12:30 +08:00
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
panic!("Cannot register indexer for arrays.");
}
#[cfg(not(feature = "no_object"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<A>() == TypeId::of::<crate::Map>() {
panic!("Cannot register indexer for object maps.");
}
if TypeId::of::<A>() == TypeId::of::<String>()
|| TypeId::of::<A>() == TypeId::of::<&str>()
|| TypeId::of::<A>() == TypeId::of::<ImmutableString>()
{
panic!("Cannot register indexer for strings.");
}
self.set_fn(
2021-03-15 12:39:06 +08:00
crate::engine::FN_IDX_GET,
FnNamespace::Global,
2020-10-01 23:31:27 +08:00
FnAccess::Public,
2020-11-22 17:21:34 +08:00
None,
2021-03-15 12:39:06 +08:00
&F::param_types(),
func.into_callable_function(),
)
2020-05-05 17:51:40 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`],
2021-12-06 10:34:13 +08:00
/// returning a non-zero hash key.
/// This function is automatically exposed to the global namespace.
2020-06-06 13:06:00 +08:00
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Panics
///
2021-12-06 20:52:47 +08:00
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
/// Indexers for arrays, object maps and strings cannot be registered.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
2020-06-06 13:06:00 +08:00
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_indexer_set_fn(|x: &mut i64, y: ImmutableString, value: i64| {
2021-04-19 15:41:24 +08:00
/// *x = y.len() as i64 + value; Ok(())
2020-06-06 13:06:00 +08:00
/// });
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash));
2020-06-06 13:06:00 +08:00
/// ```
2021-05-18 20:12:30 +08:00
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline]
pub fn set_indexer_set_fn<A, B, T, F, S>(&mut self, func: F) -> u64
2021-03-15 12:39:06 +08:00
where
A: Variant + Clone,
B: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S>> + SendSync + 'static,
2021-03-15 12:39:06 +08:00
{
2021-05-18 20:12:30 +08:00
#[cfg(not(feature = "no_index"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
panic!("Cannot register indexer for arrays.");
}
#[cfg(not(feature = "no_object"))]
2021-12-06 20:52:47 +08:00
if TypeId::of::<A>() == TypeId::of::<crate::Map>() {
panic!("Cannot register indexer for object maps.");
}
if TypeId::of::<A>() == TypeId::of::<String>()
|| TypeId::of::<A>() == TypeId::of::<&str>()
|| TypeId::of::<A>() == TypeId::of::<ImmutableString>()
{
panic!("Cannot register indexer for strings.");
}
2020-06-06 13:06:00 +08:00
self.set_fn(
2020-11-16 16:28:04 +08:00
crate::engine::FN_IDX_SET,
2021-03-15 12:39:06 +08:00
FnNamespace::Global,
2020-10-01 23:31:27 +08:00
FnAccess::Public,
2020-11-22 17:21:34 +08:00
None,
2021-03-15 12:39:06 +08:00
&F::param_types(),
func.into_callable_function(),
2020-06-06 13:06:00 +08:00
)
}
2022-08-22 00:15:00 +08:00
/// Set a pair of Rust index getter and setter functions into the [`Module`], returning both non-zero hash keys.
2020-11-20 16:52:28 +08:00
/// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and
/// [`set_indexer_set_fn`][Module::set_indexer_set_fn].
2020-07-24 23:16:54 +08:00
///
2022-08-22 00:15:00 +08:00
/// These functions are automatically exposed to the global namespace.
///
2020-07-24 23:16:54 +08:00
/// If there are similar existing Rust functions, they are replaced.
///
/// # Panics
///
2021-12-06 20:52:47 +08:00
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
/// Indexers for arrays, object maps and strings cannot be registered.
///
2020-11-22 22:15:17 +08:00
/// # Function Metadata
///
2021-12-21 22:16:03 +08:00
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
2020-11-22 22:15:17 +08:00
///
2020-10-27 11:30:38 +08:00
/// # Example
2020-07-24 23:16:54 +08:00
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let (hash_get, hash_set) = module.set_indexer_get_set_fn(
/// |x: &mut i64, y: ImmutableString| {
/// Ok(*x + y.len() as i64)
/// },
/// |x: &mut i64, y: ImmutableString, value: i64| {
2021-04-19 15:41:24 +08:00
/// *x = y.len() as i64 + value; Ok(())
2020-07-24 23:16:54 +08:00
/// }
/// );
2021-03-17 14:45:40 +08:00
/// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set));
2020-07-24 23:16:54 +08:00
/// ```
2021-05-18 20:12:30 +08:00
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
2021-01-03 13:29:42 +08:00
#[inline(always)]
2022-08-24 18:27:58 +08:00
pub fn set_indexer_get_set_fn<
2021-03-24 13:17:52 +08:00
A: Variant + Clone,
B: Variant + Clone,
T: Variant + Clone,
2022-08-24 18:27:58 +08:00
S1,
S2,
>(
&mut self,
get_fn: impl RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S1>> + SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S2>> + SendSync + 'static,
) -> (u64, u64) {
2020-07-24 23:16:54 +08:00
(
2021-02-13 10:56:09 +08:00
self.set_indexer_get_fn(get_fn),
self.set_indexer_set_fn(set_fn),
2020-07-24 23:16:54 +08:00
)
}
/// Look up a Rust function by hash.
2020-05-05 17:51:40 +08:00
///
2021-03-15 12:39:06 +08:00
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> {
2022-07-27 18:04:59 +08:00
if self.functions.is_empty() {
2022-03-03 13:02:57 +08:00
None
2022-07-27 18:04:59 +08:00
} else {
self.functions.get(&hash_native).map(|f| &f.func)
2022-03-03 13:02:57 +08:00
}
2020-05-05 17:51:40 +08:00
}
2022-09-08 17:49:37 +08:00
/// Can the particular function with [`Dynamic`] parameter(s) exist in the [`Module`]?
///
/// A `true` return value does not automatically imply that the function _must_ exist.
#[inline(always)]
#[must_use]
2022-09-08 17:49:37 +08:00
pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool {
!self.dynamic_functions_filter.is_absent(hash_script)
}
2021-01-02 23:30:10 +08:00
/// Does the particular namespace-qualified function exist in the [`Module`]?
///
2021-03-08 15:30:32 +08:00
/// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
2020-12-24 16:32:43 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-03-08 15:30:32 +08:00
pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool {
2022-09-13 18:23:34 +08:00
self.all_functions
.as_ref()
.map_or(false, |m| m.contains_key(&hash_fn))
}
2020-11-10 23:26:50 +08:00
/// Get a namespace-qualified function.
2020-05-05 17:51:40 +08:00
///
2021-03-08 15:30:32 +08:00
/// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
2022-01-29 11:09:43 +08:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2021-03-08 15:30:32 +08:00
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
2022-09-13 18:23:34 +08:00
self.all_functions
.as_ref()
.and_then(|m| m.get(&hash_qualified_fn))
2020-05-05 17:51:40 +08:00
}
2020-05-05 23:57:25 +08:00
2021-01-02 23:30:10 +08:00
/// Combine another [`Module`] into this [`Module`].
/// The other [`Module`] is _consumed_ to merge into this [`Module`].
2020-10-08 22:25:50 +08:00
#[inline]
2020-08-15 00:04:10 +08:00
pub fn combine(&mut self, other: Self) -> &mut Self {
2022-09-13 18:23:34 +08:00
match self.modules {
Some(ref mut m) if other.modules.is_some() => {
m.extend(other.modules.unwrap().into_iter())
}
Some(_) => (),
None => self.modules = other.modules,
}
match self.variables {
Some(ref mut m) if other.variables.is_some() => {
m.extend(other.variables.unwrap().into_iter())
}
Some(_) => (),
None => self.variables = other.variables,
}
2020-10-25 00:39:47 +08:00
self.functions.extend(other.functions.into_iter());
self.dynamic_functions_filter += &other.dynamic_functions_filter;
2022-09-13 18:23:34 +08:00
match self.type_iterators {
Some(ref mut m) if other.type_iterators.is_some() => {
m.extend(other.type_iterators.unwrap().into_iter())
}
Some(_) => (),
None => self.type_iterators = other.type_iterators,
}
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
self.indexed = false;
self.contains_indexed_global_functions = false;
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
if !other.doc.is_empty() {
if !self.doc.is_empty() {
self.doc.push('\n');
}
self.doc.push_str(&other.doc);
}
self
}
2021-01-02 23:30:10 +08:00
/// Combine another [`Module`] into this [`Module`].
/// The other [`Module`] is _consumed_ to merge into this [`Module`].
/// Sub-modules are flattened onto the root [`Module`], with higher level overriding lower level.
2020-10-08 22:25:50 +08:00
#[inline]
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
2022-09-13 18:23:34 +08:00
if let Some(modules) = other.modules {
for m in modules.into_values() {
self.combine_flatten(shared_take_or_clone(m));
}
}
match self.variables {
Some(ref mut m) if other.variables.is_some() => {
m.extend(other.variables.unwrap().into_iter())
}
Some(_) => (),
None => self.variables = other.variables,
2022-01-28 18:59:18 +08:00
}
2020-10-25 00:39:47 +08:00
self.functions.extend(other.functions.into_iter());
self.dynamic_functions_filter += &other.dynamic_functions_filter;
2022-09-13 18:23:34 +08:00
match self.type_iterators {
Some(ref mut m) if other.type_iterators.is_some() => {
m.extend(other.type_iterators.unwrap().into_iter())
}
Some(_) => (),
None => self.type_iterators = other.type_iterators,
}
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
2020-10-25 00:39:47 +08:00
self.indexed = false;
self.contains_indexed_global_functions = false;
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
if !other.doc.is_empty() {
if !self.doc.is_empty() {
self.doc.push('\n');
}
self.doc.push_str(&other.doc);
}
2020-10-25 00:39:47 +08:00
self
}
2021-01-02 23:30:10 +08:00
/// Polyfill this [`Module`] with another [`Module`].
/// Only items not existing in this [`Module`] are added.
2020-10-25 00:39:47 +08:00
#[inline]
pub fn fill_with(&mut self, other: &Self) -> &mut Self {
2022-09-13 18:23:34 +08:00
if let Some(ref modules) = other.modules {
let m = self.modules.get_or_insert_with(|| Default::default());
for (k, v) in modules {
if !m.contains_key(k) {
m.insert(k.clone(), v.clone());
}
2020-10-25 00:39:47 +08:00
}
2022-01-28 18:59:18 +08:00
}
2022-09-13 18:23:34 +08:00
if let Some(ref variables) = other.variables {
for (k, v) in variables {
let m = self.variables.get_or_insert_with(|| Default::default());
if !m.contains_key(k) {
m.insert(k.clone(), v.clone());
}
2020-10-25 00:39:47 +08:00
}
2022-01-28 18:59:18 +08:00
}
for (&k, v) in &other.functions {
2020-10-25 00:39:47 +08:00
self.functions.entry(k).or_insert_with(|| v.clone());
2022-01-28 18:59:18 +08:00
}
self.dynamic_functions_filter += &other.dynamic_functions_filter;
2022-09-13 18:23:34 +08:00
if let Some(ref type_iterators) = other.type_iterators {
let t = self
.type_iterators
.get_or_insert_with(|| Default::default());
for (&k, v) in type_iterators {
t.entry(k).or_insert_with(|| v.clone());
}
2022-01-28 18:59:18 +08:00
}
2022-09-13 18:23:34 +08:00
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
2020-08-15 00:04:10 +08:00
self.indexed = false;
self.contains_indexed_global_functions = false;
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
if !other.doc.is_empty() {
if !self.doc.is_empty() {
self.doc.push('\n');
}
self.doc.push_str(&other.doc);
}
2020-08-15 00:04:10 +08:00
self
}
2021-01-02 23:30:10 +08:00
/// Merge another [`Module`] into this [`Module`].
2020-10-08 22:25:50 +08:00
#[inline(always)]
2020-07-12 11:46:53 +08:00
pub fn merge(&mut self, other: &Self) -> &mut Self {
self.merge_filtered(other, |_, _, _, _, _| true)
}
2021-01-02 23:30:10 +08:00
/// Merge another [`Module`] into this [`Module`] based on a filter predicate.
pub(crate) fn merge_filtered(
&mut self,
other: &Self,
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool + Copy,
2020-07-12 11:46:53 +08:00
) -> &mut Self {
2022-09-13 18:23:34 +08:00
if let Some(ref modules) = other.modules {
for (k, v) in modules {
let mut m = Self::new();
m.merge_filtered(v, _filter);
self.set_sub_module(k.clone(), m);
}
#[cfg(feature = "no_function")]
if let Some(ref mut m) = self.modules {
m.extend(modules.iter().map(|(k, v)| (k.clone(), v.clone())));
} else {
2022-09-13 21:12:44 +08:00
self.modules = Some(modules.clone());
2022-09-13 18:23:34 +08:00
}
2022-01-28 18:59:18 +08:00
}
2020-10-25 00:39:47 +08:00
2022-09-13 18:23:34 +08:00
if let Some(ref variables) = other.variables {
2022-10-10 16:46:35 +08:00
match self.variables {
Some(ref mut m) => m.extend(variables.iter().map(|(k, v)| (k.clone(), v.clone()))),
None => self.variables = other.variables.clone(),
2022-09-13 18:23:34 +08:00
}
}
2020-10-25 00:39:47 +08:00
self.functions.extend(
other
.functions
.iter()
2022-02-08 09:02:15 +08:00
.filter(|&(.., f)| {
2021-03-12 14:11:08 +08:00
_filter(
2022-09-08 17:49:37 +08:00
f.namespace,
f.access,
2021-03-12 14:11:08 +08:00
f.func.is_script(),
2022-09-08 17:49:37 +08:00
f.name.as_str(),
f.num_params,
2021-03-12 14:11:08 +08:00
)
})
2020-10-25 00:39:47 +08:00
.map(|(&k, v)| (k, v.clone())),
);
self.dynamic_functions_filter += &other.dynamic_functions_filter;
2022-09-13 18:23:34 +08:00
if let Some(ref type_iterators) = other.type_iterators {
2022-10-10 16:46:35 +08:00
match self.type_iterators {
Some(ref mut t) => t.extend(type_iterators.iter().map(|(&k, v)| (k, v.clone()))),
None => self.type_iterators = other.type_iterators.clone(),
2022-09-13 18:23:34 +08:00
}
}
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
self.indexed = false;
self.contains_indexed_global_functions = false;
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
if !other.doc.is_empty() {
if !self.doc.is_empty() {
self.doc.push('\n');
}
self.doc.push_str(&other.doc);
}
2020-07-12 11:46:53 +08:00
self
}
2020-11-17 12:23:53 +08:00
/// Filter out the functions, retaining only some script-defined functions based on a filter predicate.
2020-07-04 16:21:15 +08:00
#[cfg(not(feature = "no_function"))]
2020-10-08 22:25:50 +08:00
#[inline]
2020-11-17 12:23:53 +08:00
pub(crate) fn retain_script_functions(
2020-07-12 11:46:53 +08:00
&mut self,
2021-02-13 10:56:09 +08:00
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
2020-07-12 11:46:53 +08:00
) -> &mut Self {
2021-04-17 15:15:54 +08:00
self.functions = std::mem::take(&mut self.functions)
2021-03-23 12:13:53 +08:00
.into_iter()
2022-02-08 09:02:15 +08:00
.filter(|(.., f)| {
2021-03-23 12:13:53 +08:00
if f.func.is_script() {
2022-09-08 17:49:37 +08:00
filter(f.namespace, f.access, f.name.as_str(), f.num_params)
2021-03-23 12:13:53 +08:00
} else {
false
}
})
.collect();
self.dynamic_functions_filter.clear();
2022-09-13 18:23:34 +08:00
self.all_functions = None;
self.all_variables = None;
self.all_type_iterators = None;
self.indexed = false;
self.contains_indexed_global_functions = false;
2020-07-12 11:46:53 +08:00
self
}
2021-01-02 23:30:10 +08:00
/// Get the number of variables, functions and type iterators in the [`Module`].
2020-10-08 22:25:50 +08:00
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-10-05 21:52:39 +08:00
pub fn count(&self) -> (usize, usize, usize) {
(
2022-09-13 18:23:34 +08:00
self.variables.as_ref().map_or(0, |m| m.len()),
2020-11-09 22:44:20 +08:00
self.functions.len(),
2022-09-13 18:23:34 +08:00
self.type_iterators.as_ref().map_or(0, |t| t.len()),
2020-10-05 21:52:39 +08:00
)
}
2021-01-02 23:30:10 +08:00
/// Get an iterator to the sub-modules in the [`Module`].
#[inline]
pub fn iter_sub_modules(&self) -> impl Iterator<Item = (&str, &Shared<Module>)> {
2022-09-13 18:23:34 +08:00
self.modules
.iter()
.flat_map(|m| m.iter().map(|(k, m)| (k.as_str(), m)))
2020-11-23 19:11:32 +08:00
}
2021-01-02 23:30:10 +08:00
/// Get an iterator to the variables in the [`Module`].
#[inline]
2020-11-23 19:11:32 +08:00
pub fn iter_var(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
2022-09-13 18:23:34 +08:00
self.variables
.iter()
.flat_map(|m| m.iter().map(|(k, v)| (k.as_str(), v)))
}
2021-01-02 23:30:10 +08:00
/// Get an iterator to the functions in the [`Module`].
#[inline]
2021-01-18 10:56:42 +08:00
#[allow(dead_code)]
pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> {
self.functions.values()
}
2021-01-02 23:30:10 +08:00
/// Get an iterator over all script-defined functions in the [`Module`].
2020-10-05 21:52:39 +08:00
///
/// Function metadata includes:
2020-11-20 16:52:28 +08:00
/// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
/// 3) Function name (as string slice).
/// 4) Number of parameters.
2020-11-25 09:36:06 +08:00
/// 5) Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
2020-07-04 16:21:15 +08:00
#[cfg(not(feature = "no_function"))]
#[inline]
2021-02-09 14:22:55 +08:00
pub(crate) fn iter_script_fn(
&self,
2021-03-12 14:11:08 +08:00
) -> impl Iterator<
Item = (
FnNamespace,
FnAccess,
&str,
usize,
&Shared<crate::ast::ScriptFnDef>,
),
> + '_ {
2021-12-06 11:12:54 +08:00
self.iter_fn().filter(|&f| f.func.is_script()).map(|f| {
(
2022-09-08 17:49:37 +08:00
f.namespace,
f.access,
f.name.as_str(),
f.num_params,
2021-12-17 16:07:13 +08:00
f.func.get_script_fn_def().expect("script-defined function"),
2021-12-06 11:12:54 +08:00
)
})
}
2021-01-02 23:30:10 +08:00
/// Get an iterator over all script-defined functions in the [`Module`].
2020-10-05 21:52:39 +08:00
///
/// Function metadata includes:
2020-11-20 16:52:28 +08:00
/// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
/// 3) Function name (as string slice).
/// 4) Number of parameters.
2020-10-05 21:52:39 +08:00
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "internals"))]
#[inline]
2020-11-17 12:23:53 +08:00
pub fn iter_script_fn_info(
&self,
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> {
2022-09-08 17:49:37 +08:00
self.iter_fn()
.filter(|&f| f.func.is_script())
2022-09-10 13:49:21 +08:00
.map(|f| (f.namespace, f.access, f.name.as_str(), f.num_params))
2020-10-05 21:52:39 +08:00
}
2021-07-25 22:56:05 +08:00
/// _(internals)_ Get an iterator over all script-defined functions in the [`Module`].
2021-02-21 14:26:31 +08:00
/// Exported under the `internals` feature only.
2020-10-05 21:52:39 +08:00
///
/// Function metadata includes:
2020-11-20 16:52:28 +08:00
/// 1) Namespace ([`FnNamespace::Global`] or [`FnNamespace::Internal`]).
/// 2) Access mode ([`FnAccess::Public`] or [`FnAccess::Private`]).
/// 3) Function name (as string slice).
/// 4) Number of parameters.
2021-07-25 22:56:05 +08:00
/// 5) _(internals)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
2020-10-05 21:52:39 +08:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "internals")]
#[inline(always)]
pub fn iter_script_fn_info(
&self,
2021-03-12 19:33:22 +08:00
) -> impl Iterator<
Item = (
FnNamespace,
FnAccess,
&str,
usize,
&Shared<crate::ast::ScriptFnDef>,
),
> {
2020-10-05 21:52:39 +08:00
self.iter_script_fn()
}
2021-01-02 23:30:10 +08:00
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
///
/// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions to
/// cross-call each other.
///
2020-10-27 11:30:38 +08:00
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// use rhai::{Engine, Module, Scope};
///
/// let engine = Engine::new();
/// let ast = engine.compile("let answer = 42; export answer;")?;
/// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
/// assert!(module.contains_var("answer"));
2021-08-26 23:58:41 +08:00
/// assert_eq!(module.get_var_value::<i64>("answer").expect("answer should exist"), 42);
/// # Ok(())
/// # }
/// ```
2020-05-13 19:21:42 +08:00
#[cfg(not(feature = "no_module"))]
2022-01-28 18:59:18 +08:00
#[inline(always)]
pub fn eval_ast_as_new(
2021-11-16 13:15:43 +08:00
scope: crate::Scope,
2020-11-16 16:28:04 +08:00
ast: &crate::AST,
engine: &crate::Engine,
2021-12-25 23:49:14 +08:00
) -> RhaiResultOf<Self> {
2022-01-28 18:59:18 +08:00
let global = &mut crate::eval::GlobalRuntimeState::new(engine);
2022-01-24 17:04:40 +08:00
2022-01-28 18:59:18 +08:00
Self::eval_ast_as_new_raw(engine, scope, global, ast)
}
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
///
2022-02-23 15:43:27 +08:00
/// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions to
/// cross-call each other.
///
/// # WARNING - Low Level API
///
/// This function is very low level.
///
2022-08-10 12:48:37 +08:00
/// In particular, the [`global`][crate::GlobalRuntimeState] parameter allows the entire
/// calling environment to be encapsulated, including automatic global constants.
2022-01-28 18:59:18 +08:00
#[cfg(not(feature = "no_module"))]
pub fn eval_ast_as_new_raw(
2022-01-28 18:59:18 +08:00
engine: &crate::Engine,
scope: crate::Scope,
global: &mut crate::eval::GlobalRuntimeState,
ast: &crate::AST,
) -> RhaiResultOf<Self> {
let mut scope = scope;
2022-01-24 17:04:40 +08:00
2022-01-28 18:59:18 +08:00
// Save global state
2022-01-24 17:04:40 +08:00
let orig_imports_len = global.num_imports();
2022-01-28 18:59:18 +08:00
let orig_source = global.source.clone();
2022-01-28 21:35:16 +08:00
#[cfg(not(feature = "no_function"))]
2022-01-28 18:59:18 +08:00
let orig_constants = std::mem::take(&mut global.constants);
// Run the script
2022-11-04 21:47:09 +08:00
let caches = &mut Caches::new();
let result = engine.eval_ast_with_scope_raw(global, caches, 0, &mut scope, ast);
// Create new module
2022-01-28 18:59:18 +08:00
let mut module = Module::new();
2022-01-28 18:59:18 +08:00
// Extra modules left become sub-modules
let mut imports = StaticVec::new_const();
2020-11-15 23:14:16 +08:00
2022-01-28 18:59:18 +08:00
if result.is_ok() {
global
.scan_imports_raw()
.skip(orig_imports_len)
.for_each(|(k, m)| {
imports.push((k.clone(), m.clone()));
2022-01-28 18:59:18 +08:00
module.set_sub_module(k.clone(), m.clone());
});
}
// Restore global state
2022-01-28 21:35:16 +08:00
#[cfg(not(feature = "no_function"))]
let constants = std::mem::replace(&mut global.constants, orig_constants);
2022-01-28 18:59:18 +08:00
global.truncate_imports(orig_imports_len);
global.source = orig_source;
2022-01-07 12:19:01 +08:00
2022-01-28 18:59:18 +08:00
result?;
// Variables with an alias left in the scope become module variables
2022-02-25 10:03:34 +08:00
for (_name, value, mut aliases) in scope {
2022-02-25 09:00:15 +08:00
// It is an error to export function pointers that refer to encapsulated local functions
#[cfg(not(feature = "no_function"))]
if let Some(fn_ptr) = value.downcast_ref::<crate::FnPtr>() {
if ast.iter_fn_def().any(|f| f.name == fn_ptr.fn_name()) {
return Err(crate::ERR::ErrorMismatchDataType(
2022-08-21 17:35:44 +08:00
String::new(),
if fn_ptr.is_anonymous() {
2022-08-11 19:01:23 +08:00
format!("cannot export closure in variable {_name}")
} else {
format!(
2022-08-11 19:01:23 +08:00
"cannot export function pointer to local function '{}' in variable {_name}",
fn_ptr.fn_name()
)
},
crate::Position::NONE,
)
.into());
}
}
2022-01-28 18:59:18 +08:00
match aliases.len() {
0 => (),
1 => {
let alias = aliases.pop().unwrap();
module.set_var(alias, value);
}
_ => {
let last_alias = aliases.pop().unwrap();
for alias in aliases {
module.set_var(alias, value.clone());
}
// Avoid cloning the last value
module.set_var(last_alias, value);
}
}
}
2021-12-28 11:42:52 +08:00
// Non-private functions defined become module functions
#[cfg(not(feature = "no_function"))]
{
2022-08-24 20:59:11 +08:00
let environ = Shared::new(crate::ast::EncapsulatedEnviron {
lib: ast.shared_lib().clone(),
2022-08-25 08:41:09 +08:00
imports: imports.into_boxed_slice(),
constants,
2022-08-24 20:59:11 +08:00
});
2021-11-28 22:57:28 +08:00
ast.shared_lib()
2021-12-06 11:12:54 +08:00
.iter_fn()
2022-09-08 17:49:37 +08:00
.filter(|&f| match f.access {
2021-11-27 14:24:36 +08:00
FnAccess::Public => true,
FnAccess::Private => false,
})
2021-12-06 11:12:54 +08:00
.filter(|&f| f.func.is_script())
2021-11-27 14:24:36 +08:00
.for_each(|f| {
let mut func = f
.func
.get_script_fn_def()
2021-12-17 16:07:13 +08:00
.expect("script-defined function")
2021-11-27 14:24:36 +08:00
.as_ref()
.clone();
// Encapsulate AST environment
2022-08-24 20:59:11 +08:00
func.environ = Some(environ.clone());
2021-11-27 14:24:36 +08:00
module.set_script_fn(func);
});
}
2022-10-29 14:12:18 +08:00
module.id = ast.source_raw().cloned();
2022-07-25 17:42:15 +08:00
#[cfg(feature = "metadata")]
module.set_doc(ast.doc());
2020-11-21 22:18:32 +08:00
module.build_index();
Ok(module)
}
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
///
/// # Panics
///
/// Panics if the [`Module`] is not yet indexed via [`build_index`][Module::build_index].
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn contains_indexed_global_functions(&self) -> bool {
self.contains_indexed_global_functions
}
2021-01-02 23:30:10 +08:00
/// Scan through all the sub-modules in the [`Module`] and build a hash index of all
/// variables and functions as one flattened namespace.
///
2021-01-02 23:30:10 +08:00
/// If the [`Module`] is already indexed, this method has no effect.
2020-11-21 22:18:32 +08:00
pub fn build_index(&mut self) -> &mut Self {
// Collect a particular module.
2020-05-09 10:00:59 +08:00
fn index_module<'a>(
2020-05-17 22:19:49 +08:00
module: &'a Module,
2021-03-12 22:30:08 +08:00
path: &mut Vec<&'a str>,
2022-09-12 23:08:38 +08:00
variables: &mut StraightHashMap<Dynamic>,
functions: &mut StraightHashMap<CallableFunction>,
2022-09-05 21:17:07 +08:00
type_iterators: &mut BTreeMap<TypeId, Shared<IteratorFn>>,
) -> bool {
let mut contains_indexed_global_functions = false;
2022-09-13 18:23:34 +08:00
if let Some(ref modules) = module.modules {
for (name, m) in modules {
// Index all the sub-modules first.
path.push(name);
if index_module(m, path, variables, functions, type_iterators) {
contains_indexed_global_functions = true;
}
path.pop();
}
2022-01-28 18:59:18 +08:00
}
2020-05-09 10:00:59 +08:00
// Index all variables
2022-09-13 18:23:34 +08:00
if let Some(ref v) = module.variables {
for (var_name, value) in v {
2022-09-21 11:46:23 +08:00
let hash_var = crate::calc_var_hash(path.iter().copied(), var_name);
2022-09-13 18:23:34 +08:00
variables.insert(hash_var, value.clone());
}
2022-01-28 18:59:18 +08:00
}
// Index type iterators
2022-09-13 18:23:34 +08:00
if let Some(ref t) = module.type_iterators {
for (&type_id, func) in t {
type_iterators.insert(type_id, func.clone());
}
2022-01-28 18:59:18 +08:00
}
2020-05-09 10:00:59 +08:00
// Index all Rust functions
2022-01-28 18:59:18 +08:00
for (&hash, f) in &module.functions {
2022-09-08 17:49:37 +08:00
match f.namespace {
2021-03-12 14:11:08 +08:00
FnNamespace::Global => {
// Flatten all functions with global namespace
functions.insert(hash, f.func.clone());
contains_indexed_global_functions = true;
}
2021-03-12 14:11:08 +08:00
FnNamespace::Internal => (),
}
2022-09-08 17:49:37 +08:00
match f.access {
2021-03-12 14:11:08 +08:00
FnAccess::Public => (),
2022-01-28 18:59:18 +08:00
FnAccess::Private => continue, // Do not index private functions
2021-03-12 14:11:08 +08:00
}
2021-03-12 14:11:08 +08:00
if !f.func.is_script() {
2022-09-08 17:49:37 +08:00
let hash_qualified_fn =
calc_native_fn_hash(path.iter().copied(), f.name.as_str(), &f.param_types);
2021-03-12 14:11:08 +08:00
functions.insert(hash_qualified_fn, f.func.clone());
} else if cfg!(not(feature = "no_function")) {
2022-09-08 17:49:37 +08:00
let hash_qualified_script =
2022-09-21 11:46:23 +08:00
crate::calc_fn_hash(path.iter().copied(), &f.name, f.num_params);
2021-03-12 14:11:08 +08:00
functions.insert(hash_qualified_script, f.func.clone());
}
2022-01-28 18:59:18 +08:00
}
contains_indexed_global_functions
}
2020-10-01 23:31:27 +08:00
if !self.indexed {
2021-03-12 22:30:08 +08:00
let mut path = Vec::with_capacity(4);
let mut variables = StraightHashMap::default();
let mut functions = StraightHashMap::default();
2022-09-05 21:17:07 +08:00
let mut type_iterators = BTreeMap::new();
2020-07-26 15:53:22 +08:00
2021-04-17 22:19:48 +08:00
path.push("");
self.contains_indexed_global_functions = index_module(
self,
2021-03-12 22:30:08 +08:00
&mut path,
&mut variables,
&mut functions,
&mut type_iterators,
);
2022-09-13 18:23:34 +08:00
self.all_variables = if variables.is_empty() {
None
} else {
Some(variables)
};
self.all_functions = if functions.is_empty() {
None
} else {
Some(functions)
};
self.all_type_iterators = if type_iterators.is_empty() {
None
} else {
Some(type_iterators)
};
2020-10-01 23:31:27 +08:00
self.indexed = true;
}
2020-11-21 22:18:32 +08:00
self
}
2020-05-13 19:21:42 +08:00
/// Does a type iterator exist in the entire module tree?
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
2022-09-13 18:23:34 +08:00
self.all_type_iterators
.as_ref()
.map_or(false, |t| t.contains_key(&id))
}
2020-05-13 19:21:42 +08:00
/// Does a type iterator exist in the module?
#[inline(always)]
2021-06-12 22:47:43 +08:00
#[must_use]
2020-05-13 20:22:05 +08:00
pub fn contains_iter(&self, id: TypeId) -> bool {
2022-09-13 18:23:34 +08:00
self.type_iterators
.as_ref()
.map_or(false, |t| t.contains_key(&id))
2020-05-13 19:21:42 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a type iterator into the [`Module`].
2022-08-22 13:10:32 +08:00
#[inline(always)]
2022-01-27 23:55:32 +08:00
pub fn set_iter(
&mut self,
type_id: TypeId,
2022-08-22 14:02:24 +08:00
func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + SendSync + 'static,
2022-08-22 13:10:32 +08:00
) -> &mut Self {
self.set_iter_result(type_id, move |x| {
Box::new(func(x).map(Ok)) as Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>
})
}
/// Set a fallible type iterator into the [`Module`].
#[inline]
pub fn set_iter_result(
&mut self,
type_id: TypeId,
2022-08-22 14:02:24 +08:00
func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + SendSync + 'static,
2022-01-27 23:55:32 +08:00
) -> &mut Self {
let func = Shared::new(func);
2021-04-17 22:19:48 +08:00
if self.indexed {
2022-09-13 18:23:34 +08:00
self.all_type_iterators
.get_or_insert_with(|| Default::default())
.insert(type_id, func.clone());
2021-04-17 22:19:48 +08:00
}
2022-09-13 18:23:34 +08:00
self.type_iterators
.get_or_insert_with(|| Default::default())
.insert(type_id, func);
2020-07-12 11:46:53 +08:00
self
2020-05-13 19:21:42 +08:00
}
2021-01-02 23:30:10 +08:00
/// Set a type iterator into the [`Module`].
2022-08-22 14:02:24 +08:00
#[inline(always)]
2020-10-15 22:11:18 +08:00
pub fn set_iterable<T>(&mut self) -> &mut Self
where
T: Variant + Clone + IntoIterator,
<T as IntoIterator>::Item: Variant + Clone,
{
2020-10-14 23:22:10 +08:00
self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().into_iter().map(Dynamic::from))
})
}
2022-08-22 14:02:24 +08:00
/// Set a fallible type iterator into the [`Module`].
#[inline(always)]
pub fn set_iterable_result<T, X>(&mut self) -> &mut Self
where
T: Variant + Clone + IntoIterator<Item = RhaiResultOf<X>>,
X: Variant + Clone,
{
self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().into_iter().map(|v| v.map(Dynamic::from)))
})
}
2021-01-02 23:30:10 +08:00
/// Set an iterator type into the [`Module`] as a type iterator.
2022-08-22 14:02:24 +08:00
#[inline(always)]
2020-10-15 22:11:18 +08:00
pub fn set_iterator<T>(&mut self) -> &mut Self
where
T: Variant + Clone + Iterator,
<T as Iterator>::Item: Variant + Clone,
{
2020-10-14 23:22:10 +08:00
self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().map(Dynamic::from))
})
}
2022-08-22 14:02:24 +08:00
/// Set a iterator type into the [`Module`] as a fallible type iterator.
#[inline(always)]
pub fn set_iterator_result<T, X>(&mut self) -> &mut Self
where
T: Variant + Clone + Iterator<Item = RhaiResultOf<X>>,
X: Variant + Clone,
{
self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().map(|v| v.map(Dynamic::from)))
})
}
/// Get the specified type iterator.
2022-01-29 11:09:43 +08:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-27 23:55:32 +08:00
pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> {
2022-09-13 18:23:34 +08:00
self.all_type_iterators
.as_ref()
.and_then(|t| t.get(&id))
.map(|f| &**f)
}
2020-05-13 19:21:42 +08:00
/// Get the specified type iterator.
#[inline]
2021-06-12 22:47:43 +08:00
#[must_use]
2022-01-27 23:55:32 +08:00
pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> {
2022-09-13 18:23:34 +08:00
self.type_iterators
.as_ref()
.and_then(|t| t.get(&id))
.map(|f| &**f)
2020-05-13 19:21:42 +08:00
}
}
2022-01-29 11:09:43 +08:00
/// Module containing all built-in [module resolvers][ModuleResolver].
#[cfg(not(feature = "no_module"))]
pub mod resolvers;
2020-05-13 19:21:42 +08:00
2020-07-07 23:44:23 +08:00
#[cfg(not(feature = "no_module"))]
2022-01-29 11:09:43 +08:00
pub use resolvers::ModuleResolver;