2020-05-05 06:24:13 +02:00
|
|
|
//! Module defining external-loaded modules for Rhai.
|
|
|
|
|
2020-12-22 09:45:56 +01:00
|
|
|
use crate::ast::{FnAccess, Ident};
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::dynamic::Variant;
|
2020-11-21 15:18:32 +01:00
|
|
|
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
|
2020-09-19 12:12:23 +02:00
|
|
|
use crate::fn_register::by_value as cast_arg;
|
2020-05-05 17:57:25 +02:00
|
|
|
use crate::stdlib::{
|
2020-05-06 10:09:44 +02:00
|
|
|
any::TypeId,
|
2020-05-06 13:45:17 +02:00
|
|
|
boxed::Box,
|
2020-05-06 10:09:44 +02:00
|
|
|
collections::HashMap,
|
2020-06-26 17:24:47 +02:00
|
|
|
fmt, format,
|
2020-11-27 16:37:59 +01:00
|
|
|
iter::empty,
|
2020-12-24 09:32:43 +01:00
|
|
|
num::NonZeroU64,
|
2020-05-08 16:38:56 +02:00
|
|
|
num::NonZeroUsize,
|
2020-10-07 09:40:36 +02:00
|
|
|
ops::{Add, AddAssign, Deref, DerefMut},
|
2020-05-06 13:45:17 +02:00
|
|
|
string::{String, ToString},
|
2020-05-07 18:19:08 +02:00
|
|
|
vec::Vec,
|
2020-05-05 17:57:25 +02:00
|
|
|
};
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::token::Token;
|
2020-12-24 11:43:04 +01:00
|
|
|
use crate::utils::{combine_hashes, StraightHasherBuilder};
|
2020-11-16 16:10:14 +01:00
|
|
|
use crate::{
|
2020-11-20 09:52:28 +01:00
|
|
|
Dynamic, EvalAltResult, ImmutableString, NativeCallContext, Position, Shared, StaticVec,
|
2020-11-16 16:10:14 +01:00
|
|
|
};
|
|
|
|
|
2020-11-25 02:36:06 +01:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
use crate::ast::ScriptFnDef;
|
|
|
|
|
2020-11-16 16:10:14 +01:00
|
|
|
#[cfg(not(feature = "no_index"))]
|
|
|
|
use crate::Array;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
use crate::Map;
|
2020-05-05 17:57:25 +02:00
|
|
|
|
2020-11-17 05:23:53 +01:00
|
|
|
/// A type representing the namespace of a function.
|
|
|
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
|
|
|
pub enum FnNamespace {
|
2020-12-26 06:05:57 +01:00
|
|
|
/// Expose to global namespace.
|
2020-11-17 05:23:53 +01:00
|
|
|
Global,
|
2020-12-26 06:05:57 +01:00
|
|
|
/// Module namespace only.
|
2020-11-17 05:23:53 +01:00
|
|
|
Internal,
|
|
|
|
}
|
|
|
|
|
2020-11-17 08:11:58 +01:00
|
|
|
impl Default for FnNamespace {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Internal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-17 05:23:53 +01:00
|
|
|
impl FnNamespace {
|
2020-11-25 02:36:06 +01:00
|
|
|
/// Is this namespace [global][FnNamespace::Global]?
|
2020-11-17 05:23:53 +01:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn is_global(self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::Global => true,
|
|
|
|
Self::Internal => false,
|
|
|
|
}
|
|
|
|
}
|
2020-11-25 02:36:06 +01:00
|
|
|
/// Is this namespace [internal][FnNamespace::Internal]?
|
2020-11-17 05:23:53 +01:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn is_internal(self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::Global => false,
|
|
|
|
Self::Internal => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-04 07:37:46 +01:00
|
|
|
/// Data structure containing a single registered function.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct FuncInfo {
|
|
|
|
/// Function instance.
|
|
|
|
pub func: CallableFunction,
|
2020-11-17 05:23:53 +01:00
|
|
|
/// Function namespace.
|
|
|
|
pub namespace: FnNamespace,
|
2020-11-04 07:37:46 +01:00
|
|
|
/// Function access mode.
|
|
|
|
pub access: FnAccess,
|
|
|
|
/// Function name.
|
|
|
|
pub name: String,
|
|
|
|
/// Number of parameters.
|
|
|
|
pub params: usize,
|
|
|
|
/// Parameter types (if applicable).
|
2020-12-23 16:29:19 +01:00
|
|
|
pub param_types: StaticVec<TypeId>,
|
2020-11-22 10:21:34 +01:00
|
|
|
/// Parameter names (if available).
|
2020-12-23 16:29:19 +01:00
|
|
|
pub param_names: StaticVec<ImmutableString>,
|
2020-11-22 10:21:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FuncInfo {
|
|
|
|
/// Generate a signature of the function.
|
|
|
|
pub fn gen_signature(&self) -> String {
|
|
|
|
let mut sig = format!("{}(", self.name);
|
|
|
|
|
2020-12-23 16:29:19 +01:00
|
|
|
if !self.param_names.is_empty() {
|
|
|
|
let mut params: Vec<_> = self
|
|
|
|
.param_names
|
|
|
|
.iter()
|
|
|
|
.map(ImmutableString::to_string)
|
|
|
|
.collect();
|
2020-11-22 15:15:17 +01:00
|
|
|
let return_type = params.pop().unwrap_or_else(|| "()".to_string());
|
2020-11-22 10:21:34 +01:00
|
|
|
sig.push_str(¶ms.join(", "));
|
2020-11-22 15:15:17 +01:00
|
|
|
if return_type != "()" {
|
|
|
|
sig.push_str(") -> ");
|
|
|
|
sig.push_str(&return_type);
|
|
|
|
} else {
|
|
|
|
sig.push_str(")");
|
|
|
|
}
|
2020-11-22 10:21:34 +01:00
|
|
|
} else {
|
|
|
|
for x in 0..self.params {
|
|
|
|
sig.push_str("_");
|
|
|
|
if x < self.params - 1 {
|
|
|
|
sig.push_str(", ");
|
|
|
|
}
|
|
|
|
}
|
2020-12-23 16:29:19 +01:00
|
|
|
|
|
|
|
if self.func.is_script() {
|
2020-12-28 02:49:54 +01:00
|
|
|
sig.push_str(")");
|
2020-12-23 16:29:19 +01:00
|
|
|
} else {
|
|
|
|
sig.push_str(") -> ?");
|
|
|
|
}
|
2020-11-22 10:21:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sig
|
|
|
|
}
|
2020-11-04 07:37:46 +01:00
|
|
|
}
|
2020-09-25 12:07:39 +02:00
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
/// A module which may contain variables, sub-modules, external Rust functions,
|
|
|
|
/// and/or script-defined functions.
|
2020-11-15 05:07:35 +01:00
|
|
|
#[derive(Clone)]
|
2020-05-05 09:00:10 +02:00
|
|
|
pub struct Module {
|
2020-12-21 15:04:46 +01:00
|
|
|
/// ID identifying the module.
|
|
|
|
id: Option<ImmutableString>,
|
2020-05-05 09:00:10 +02:00
|
|
|
/// Sub-modules.
|
2020-12-11 05:57:07 +01:00
|
|
|
modules: HashMap<ImmutableString, Shared<Module>>,
|
2021-01-02 16:30:10 +01:00
|
|
|
/// [`Module`] variables.
|
2020-12-11 05:57:07 +01:00
|
|
|
variables: HashMap<ImmutableString, Dynamic>,
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
2020-12-24 09:32:43 +01:00
|
|
|
all_variables: HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>,
|
2020-05-05 09:00:10 +02:00
|
|
|
/// External Rust functions.
|
2020-12-24 09:32:43 +01:00
|
|
|
functions: HashMap<NonZeroU64, FuncInfo, StraightHasherBuilder>,
|
2020-11-16 07:07:48 +01:00
|
|
|
/// Flattened collection of all external Rust functions, native or scripted.
|
2020-05-19 13:03:06 +02:00
|
|
|
/// including those in sub-modules.
|
2020-12-24 09:32:43 +01:00
|
|
|
all_functions: HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>,
|
2020-11-15 05:07:35 +01:00
|
|
|
/// Iterator functions, keyed by the type producing the iterator.
|
|
|
|
type_iterators: HashMap<TypeId, IteratorFn>,
|
2020-11-16 07:07:48 +01:00
|
|
|
/// Flattened collection of iterator functions, including those in sub-modules.
|
|
|
|
all_type_iterators: HashMap<TypeId, IteratorFn>,
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Is the [`Module`] indexed?
|
2020-06-27 17:56:24 +02:00
|
|
|
indexed: bool,
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2020-11-15 05:07:35 +01:00
|
|
|
impl Default for Module {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2020-12-21 15:04:46 +01:00
|
|
|
id: None,
|
2020-11-15 06:49:54 +01:00
|
|
|
modules: Default::default(),
|
|
|
|
variables: Default::default(),
|
|
|
|
all_variables: Default::default(),
|
2020-11-15 05:07:35 +01:00
|
|
|
functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder),
|
|
|
|
all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder),
|
2020-11-15 06:49:54 +01:00
|
|
|
type_iterators: Default::default(),
|
2020-11-16 07:07:48 +01:00
|
|
|
all_type_iterators: Default::default(),
|
2020-11-15 05:07:35 +01:00
|
|
|
indexed: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 09:00:10 +02:00
|
|
|
impl fmt::Debug for Module {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
2021-01-09 16:26:50 +01:00
|
|
|
"Module({}\n{}{}{})",
|
2020-12-21 15:04:46 +01:00
|
|
|
if let Some(ref id) = self.id {
|
2021-01-09 16:26:50 +01:00
|
|
|
format!("id: {:?},", id)
|
2020-12-21 15:04:46 +01:00
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
},
|
2021-01-09 16:26:50 +01:00
|
|
|
if !self.modules.is_empty() {
|
|
|
|
format!(
|
|
|
|
" modules: {}\n",
|
|
|
|
self.modules
|
|
|
|
.keys()
|
|
|
|
.map(|m| m.as_str())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
},
|
|
|
|
if !self.variables.is_empty() {
|
|
|
|
format!(
|
|
|
|
" vars: {}\n",
|
|
|
|
self.variables
|
|
|
|
.iter()
|
|
|
|
.map(|(k, v)| format!("{}={:?}", k, v))
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
},
|
|
|
|
if !self.functions.is_empty() {
|
|
|
|
format!(
|
|
|
|
" functions: {}\n",
|
|
|
|
self.functions
|
|
|
|
.values()
|
|
|
|
.map(|FuncInfo { func, .. }| func.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
"".to_string()
|
|
|
|
}
|
2020-05-05 09:00:10 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-06 07:01:57 +02:00
|
|
|
impl AsRef<Module> for Module {
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-06 07:01:57 +02:00
|
|
|
fn as_ref(&self) -> &Module {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 16:09:33 +01:00
|
|
|
impl<M: AsRef<Module>> Add<M> for &Module {
|
|
|
|
type Output = Module;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
fn add(mut self, rhs: M) -> Self::Output {
|
|
|
|
self.merge(rhs.as_ref());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<M: Into<Module>> AddAssign<M> for Module {
|
|
|
|
fn add_assign(&mut self, rhs: M) {
|
|
|
|
self.combine(rhs.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-05 06:24:13 +02:00
|
|
|
impl Module {
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Create a new [`Module`].
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 06:24:13 +02:00
|
|
|
pub fn new() -> Self {
|
2020-05-05 09:00:10 +02:00
|
|
|
Default::default()
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Create a new [`Module`] with a specified capacity for native Rust functions.
|
2020-05-13 13:39:34 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-13 13:39:34 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-13 13:39:34 +02:00
|
|
|
pub fn new_with_capacity(capacity: usize) -> Self {
|
|
|
|
Self {
|
2020-05-30 18:02:23 +02:00
|
|
|
functions: HashMap::with_capacity_and_hasher(capacity, StraightHasherBuilder),
|
2020-05-13 13:39:34 +02:00
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get the ID of the [`Module`], if any.
|
2020-12-21 15:04:46 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_id(Some("hello"));
|
|
|
|
/// assert_eq!(module.id(), Some("hello"));
|
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-12-21 15:04:46 +01:00
|
|
|
pub fn id(&self) -> Option<&str> {
|
2021-01-03 06:29:42 +01:00
|
|
|
self.id_raw().map(|s| s.as_str())
|
2020-12-21 15:04:46 +01:00
|
|
|
}
|
|
|
|
|
2021-01-03 03:08:22 +01:00
|
|
|
/// Get the ID of the [`Module`] as an [`ImmutableString`], if any.
|
2021-01-03 06:29:42 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_id(Some("hello"));
|
|
|
|
/// assert_eq!(module.id_raw().map(|s| s.as_str()), Some("hello"));
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
2021-01-03 04:25:25 +01:00
|
|
|
pub fn id_raw(&self) -> Option<&ImmutableString> {
|
|
|
|
self.id.as_ref()
|
2020-12-21 15:04:46 +01:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set the ID of the [`Module`].
|
2020-12-21 15:04:46 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_id(Some("hello"));
|
|
|
|
/// assert_eq!(module.id(), Some("hello"));
|
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-12-21 15:04:46 +01:00
|
|
|
pub fn set_id<S: Into<ImmutableString>>(&mut self, id: Option<S>) {
|
|
|
|
self.id = id.map(|s| s.into());
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Is the [`Module`] empty?
|
2020-09-30 03:57:21 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-09-30 03:57:21 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let module = Module::new();
|
|
|
|
/// assert!(module.is_empty());
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-09-30 03:57:21 +02:00
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.functions.is_empty()
|
|
|
|
&& self.all_functions.is_empty()
|
|
|
|
&& self.variables.is_empty()
|
|
|
|
&& self.all_variables.is_empty()
|
|
|
|
&& self.modules.is_empty()
|
|
|
|
&& self.type_iterators.is_empty()
|
2020-11-16 07:07:48 +01:00
|
|
|
&& self.all_type_iterators.is_empty()
|
2020-09-30 03:57:21 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Is the [`Module`] indexed?
|
2020-11-08 07:29:54 +01:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// assert!(!module.is_indexed());
|
|
|
|
///
|
2020-11-08 09:49:59 +01:00
|
|
|
/// # #[cfg(not(feature = "no_module"))]
|
|
|
|
/// # {
|
2020-11-08 07:29:54 +01:00
|
|
|
/// module.build_index();
|
|
|
|
/// assert!(module.is_indexed());
|
2020-11-08 09:49:59 +01:00
|
|
|
/// # }
|
2020-11-08 07:29:54 +01:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-11-08 07:29:54 +01:00
|
|
|
pub fn is_indexed(&self) -> bool {
|
|
|
|
self.indexed
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Generate signatures for all the functions in the [`Module`].
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-11-22 10:21:34 +01:00
|
|
|
pub fn gen_fn_signatures<'a>(&'a self) -> impl Iterator<Item = String> + 'a {
|
|
|
|
self.functions
|
|
|
|
.values()
|
|
|
|
.filter(|FuncInfo { access, .. }| !access.is_private())
|
|
|
|
.map(FuncInfo::gen_signature)
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Does a variable exist in the [`Module`]?
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert!(module.contains_var("answer"));
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 11:51:40 +02:00
|
|
|
pub fn contains_var(&self, name: &str) -> bool {
|
2020-05-05 09:00:10 +02:00
|
|
|
self.variables.contains_key(name)
|
2020-05-05 06:24:13 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get the value of a [`Module`] variable.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 11:51:40 +02:00
|
|
|
pub fn get_var_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
2020-05-07 18:19:08 +02:00
|
|
|
self.get_var(name).and_then(Dynamic::try_cast::<T>)
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get a [`Module`] variable as a [`Dynamic`].
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert_eq!(module.get_var("answer").unwrap().cast::<i64>(), 42);
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 11:51:40 +02:00
|
|
|
pub fn get_var(&self, name: &str) -> Option<Dynamic> {
|
2020-05-05 09:00:10 +02:00
|
|
|
self.variables.get(name).cloned()
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a variable into the [`Module`].
|
2020-05-05 09:00:10 +02:00
|
|
|
///
|
|
|
|
/// If there is an existing variable of the same name, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// module.set_var("answer", 42_i64);
|
|
|
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-12-11 05:57:07 +01:00
|
|
|
pub fn set_var(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<ImmutableString>,
|
|
|
|
value: impl Variant + Clone,
|
|
|
|
) -> &mut Self {
|
2020-05-13 13:21:42 +02:00
|
|
|
self.variables.insert(name.into(), Dynamic::from(value));
|
2020-06-27 17:56:24 +02:00
|
|
|
self.indexed = false;
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
/// Get a reference to a namespace-qualified variable.
|
2021-01-02 06:29:16 +01:00
|
|
|
/// Name and Position in [`EvalAltResult`] are [`None`] and [`NONE`][Position::NONE] and must be set afterwards.
|
2020-05-07 18:19:08 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated by the function [`calc_native_fn_hash`][crate::calc_native_fn_hash].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub(crate) fn get_qualified_var(
|
|
|
|
&self,
|
|
|
|
hash_var: NonZeroU64,
|
|
|
|
) -> Result<&Dynamic, Box<EvalAltResult>> {
|
|
|
|
self.all_variables.get(&hash_var).ok_or_else(|| {
|
|
|
|
EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into()
|
|
|
|
})
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a script-defined function into the [`Module`].
|
2020-06-05 09:14:42 +02:00
|
|
|
///
|
|
|
|
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
2020-09-24 17:32:54 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub(crate) fn set_script_fn(&mut self, fn_def: impl Into<Shared<ScriptFnDef>>) -> NonZeroU64 {
|
2020-11-25 02:36:06 +01:00
|
|
|
let fn_def = fn_def.into();
|
|
|
|
|
2020-06-05 09:14:42 +02:00
|
|
|
// None + function name + number of arguments.
|
2020-09-24 16:50:28 +02:00
|
|
|
let num_params = fn_def.params.len();
|
2020-12-24 09:32:43 +01:00
|
|
|
let hash_script = crate::calc_script_fn_hash(empty(), &fn_def.name, num_params).unwrap();
|
2020-11-27 16:37:59 +01:00
|
|
|
let mut param_names: StaticVec<_> = fn_def.params.iter().cloned().collect();
|
|
|
|
param_names.push("Dynamic".into());
|
2020-06-05 09:14:42 +02:00
|
|
|
self.functions.insert(
|
2020-06-11 12:13:33 +02:00
|
|
|
hash_script,
|
2020-11-04 07:37:46 +01:00
|
|
|
FuncInfo {
|
|
|
|
name: fn_def.name.to_string(),
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace: FnNamespace::Internal,
|
2020-11-04 07:37:46 +01:00
|
|
|
access: fn_def.access,
|
|
|
|
params: num_params,
|
2020-12-23 16:29:19 +01:00
|
|
|
param_types: Default::default(),
|
|
|
|
param_names,
|
2020-11-04 07:37:46 +01:00
|
|
|
func: fn_def.into(),
|
|
|
|
},
|
2020-06-05 09:14:42 +02:00
|
|
|
);
|
2020-06-27 17:56:24 +02:00
|
|
|
self.indexed = false;
|
2020-09-24 16:50:28 +02:00
|
|
|
hash_script
|
2020-06-05 09:14:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get a script-defined function in the [`Module`] based on name and number of parameters.
|
2020-10-05 06:09:45 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-10-05 04:27:31 +02:00
|
|
|
pub fn get_script_fn(
|
|
|
|
&self,
|
|
|
|
name: &str,
|
|
|
|
num_params: usize,
|
|
|
|
public_only: bool,
|
2020-11-25 02:36:06 +01:00
|
|
|
) -> Option<&ScriptFnDef> {
|
2020-10-05 04:27:31 +02:00
|
|
|
self.functions
|
|
|
|
.values()
|
2020-11-04 07:37:46 +01:00
|
|
|
.find(
|
|
|
|
|FuncInfo {
|
|
|
|
name: fn_name,
|
|
|
|
access,
|
|
|
|
params,
|
|
|
|
..
|
|
|
|
}| {
|
|
|
|
(!public_only || *access == FnAccess::Public)
|
|
|
|
&& *params == num_params
|
|
|
|
&& fn_name == name
|
|
|
|
},
|
|
|
|
)
|
2020-11-07 16:33:21 +01:00
|
|
|
.map(|FuncInfo { func, .. }| func.get_fn_def())
|
2020-10-05 04:27:31 +02:00
|
|
|
}
|
|
|
|
|
2020-12-26 06:05:57 +01:00
|
|
|
/// Get a mutable reference to the underlying [`HashMap`] of sub-modules.
|
2020-12-26 16:21:16 +01:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING
|
2020-12-26 16:21:16 +01:00
|
|
|
///
|
|
|
|
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Thus the [`Module`] is automatically set to be non-indexed.
|
2020-12-28 02:49:54 +01:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-12-26 06:05:57 +01:00
|
|
|
#[inline(always)]
|
|
|
|
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
|
|
|
// We must assume that the user has changed the sub-modules
|
|
|
|
// (otherwise why take a mutable reference?)
|
2020-12-26 16:21:16 +01:00
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
|
|
|
self.all_type_iterators.clear();
|
2020-12-26 06:05:57 +01:00
|
|
|
self.indexed = false;
|
|
|
|
|
|
|
|
&mut self.modules
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Does a sub-module exist in the [`Module`]?
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// 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 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 09:00:10 +02:00
|
|
|
pub fn contains_sub_module(&self, name: &str) -> bool {
|
|
|
|
self.modules.contains_key(name)
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get a sub-module in the [`Module`].
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// 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());
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-05-05 09:00:10 +02:00
|
|
|
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
2020-11-09 15:44:20 +01:00
|
|
|
self.modules.get(name).map(|m| m.as_ref())
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a sub-module into the [`Module`].
|
2020-05-05 09:00:10 +02:00
|
|
|
///
|
|
|
|
/// If there is an existing sub-module of the same name, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// 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());
|
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-09 15:44:20 +01:00
|
|
|
pub fn set_sub_module(
|
|
|
|
&mut self,
|
2020-12-11 05:57:07 +01:00
|
|
|
name: impl Into<ImmutableString>,
|
2020-11-09 15:44:20 +01:00
|
|
|
sub_module: impl Into<Shared<Module>>,
|
|
|
|
) -> &mut Self {
|
2020-05-05 09:00:10 +02:00
|
|
|
self.modules.insert(name.into(), sub_module.into());
|
2020-06-27 17:56:24 +02:00
|
|
|
self.indexed = false;
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-05-05 09:00:10 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Does the particular Rust function exist in the [`Module`]?
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated by the function [`calc_native_fn_hash`][crate::calc_native_fn_hash].
|
2020-05-05 11:51:40 +02:00
|
|
|
/// It is also returned by the `set_fn_XXX` calls.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-09 18:19:13 +02:00
|
|
|
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub fn contains_fn(&self, hash_fn: NonZeroU64, public_only: bool) -> bool {
|
|
|
|
if public_only {
|
2020-07-27 12:10:45 +02:00
|
|
|
self.functions
|
|
|
|
.get(&hash_fn)
|
2021-02-07 08:09:27 +01:00
|
|
|
.map_or(false, |FuncInfo { access, .. }| access.is_public())
|
2020-07-27 12:10:45 +02:00
|
|
|
} else {
|
|
|
|
self.functions.contains_key(&hash_fn)
|
|
|
|
}
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-22 15:15:17 +01:00
|
|
|
/// Update the metadata (parameter names/types and return type) of a registered function.
|
2020-11-22 10:21:34 +01:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated either by the function
|
|
|
|
/// [`calc_native_fn_hash`][crate::calc_native_fn_hash] or the function
|
|
|
|
/// [`calc_script_fn_hash`][crate::calc_script_fn_hash].
|
|
|
|
///
|
|
|
|
/// ## Parameter Names and Types
|
2020-11-22 15:15:17 +01:00
|
|
|
///
|
|
|
|
/// Each parameter name/type pair should be a single string of the format: `var_name: type`.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// ## Return Type
|
|
|
|
///
|
|
|
|
/// The _last entry_ in the list should be the _return type_ of the function.
|
2020-11-22 15:15:17 +01:00
|
|
|
/// In other words, the number of entries should be one larger than the number of parameters.
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-11-22 15:15:17 +01:00
|
|
|
pub fn update_fn_metadata<'a>(
|
|
|
|
&mut self,
|
2020-12-24 09:32:43 +01:00
|
|
|
hash_fn: NonZeroU64,
|
2020-11-22 15:15:17 +01:00
|
|
|
arg_names: impl AsRef<[&'a str]>,
|
|
|
|
) -> &mut Self {
|
2020-11-22 10:21:34 +01:00
|
|
|
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
2020-12-23 16:29:19 +01:00
|
|
|
f.param_names = arg_names.as_ref().iter().map(|&n| n.into()).collect();
|
2020-11-22 10:21:34 +01:00
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-12-07 14:54:52 +01:00
|
|
|
/// Update the namespace of a registered function.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated either by the function
|
|
|
|
/// [`calc_native_fn_hash`][crate::calc_native_fn_hash] or the function
|
|
|
|
/// [`calc_script_fn_hash`][crate::calc_script_fn_hash].
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub fn update_fn_namespace(
|
|
|
|
&mut self,
|
|
|
|
hash_fn: NonZeroU64,
|
|
|
|
namespace: FnNamespace,
|
|
|
|
) -> &mut Self {
|
2020-12-07 14:54:52 +01:00
|
|
|
if let Some(f) = self.functions.get_mut(&hash_fn) {
|
|
|
|
f.namespace = namespace;
|
|
|
|
}
|
|
|
|
self.indexed = false;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is an existing Rust function of the same hash, it is replaced.
|
2020-07-11 09:09:17 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING - Low Level API
|
2020-07-11 09:09:17 +02:00
|
|
|
///
|
|
|
|
/// This function is very low level.
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline]
|
2020-07-11 09:09:17 +02:00
|
|
|
pub fn set_fn(
|
2020-05-22 15:50:24 +02:00
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace: FnNamespace,
|
2020-05-22 15:50:24 +02:00
|
|
|
access: FnAccess,
|
2020-11-22 10:21:34 +01:00
|
|
|
arg_names: Option<&[&str]>,
|
2020-07-07 16:59:23 +02:00
|
|
|
arg_types: &[TypeId],
|
2020-09-25 12:07:39 +02:00
|
|
|
func: CallableFunction,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-05-22 15:50:24 +02:00
|
|
|
let name = name.into();
|
|
|
|
|
2020-12-24 09:32:43 +01:00
|
|
|
let hash_fn =
|
|
|
|
crate::calc_native_fn_hash(empty(), &name, arg_types.iter().cloned()).unwrap();
|
2020-09-11 16:32:59 +02:00
|
|
|
|
2020-12-23 16:29:19 +01:00
|
|
|
let param_types = arg_types
|
2020-09-19 12:12:23 +02:00
|
|
|
.into_iter()
|
|
|
|
.cloned()
|
|
|
|
.map(|id| {
|
2020-10-28 15:18:44 +01:00
|
|
|
if id == TypeId::of::<&str>() || id == TypeId::of::<String>() {
|
2020-09-19 12:12:23 +02:00
|
|
|
TypeId::of::<ImmutableString>()
|
|
|
|
} else {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
})
|
2020-10-28 15:18:44 +01:00
|
|
|
.collect::<StaticVec<_>>();
|
2020-05-17 16:19:49 +02:00
|
|
|
|
2020-10-28 15:18:44 +01:00
|
|
|
self.functions.insert(
|
|
|
|
hash_fn,
|
2020-11-04 07:37:46 +01:00
|
|
|
FuncInfo {
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace,
|
2020-11-04 07:37:46 +01:00
|
|
|
access,
|
2020-12-23 16:29:19 +01:00
|
|
|
params: param_types.len(),
|
|
|
|
param_types,
|
|
|
|
param_names: if let Some(p) = arg_names {
|
|
|
|
p.iter().map(|&v| v.into()).collect()
|
|
|
|
} else {
|
|
|
|
Default::default()
|
|
|
|
},
|
2020-11-04 07:37:46 +01:00
|
|
|
func: func.into(),
|
|
|
|
},
|
2020-10-28 15:18:44 +01:00
|
|
|
);
|
2020-05-05 17:57:25 +02:00
|
|
|
|
2020-06-27 17:56:24 +02:00
|
|
|
self.indexed = false;
|
|
|
|
|
2020-05-11 17:48:50 +02:00
|
|
|
hash_fn
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Set a Rust function taking a reference to the scripting [`Engine`][crate::Engine],
|
2020-12-26 16:21:16 +01:00
|
|
|
/// the current set of functions, plus a list of mutable [`Dynamic`] references
|
2021-01-02 16:30:10 +01:00
|
|
|
/// into the [`Module`], returning a hash key.
|
2020-06-15 15:49:02 +02:00
|
|
|
///
|
|
|
|
/// Use this to register a built-in function which must reference settings on the scripting
|
2020-11-20 09:52:28 +01: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.
|
2020-06-15 15:49:02 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING - Low Level API
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
|
|
|
/// This function is very low level.
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// A list of [`TypeId`]'s is taken as the argument types.
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][Dynamic],
|
2020-07-07 16:59:23 +02:00
|
|
|
/// which is guaranteed to contain enough arguments of the correct types.
|
|
|
|
///
|
2020-10-03 10:25:58 +02:00
|
|
|
/// The function is assumed to be a _method_, meaning that the first argument should not be consumed.
|
|
|
|
/// All other arguments can be consumed.
|
|
|
|
///
|
2020-07-07 16:59:23 +02:00
|
|
|
/// To access a primary parameter value (i.e. cloning is cheap), use: `args[n].clone().cast::<T>()`
|
|
|
|
///
|
|
|
|
/// To access a parameter value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`.
|
|
|
|
/// Notice that this will _consume_ the argument, replacing it with `()`.
|
|
|
|
///
|
|
|
|
/// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-11-17 05:23:53 +01:00
|
|
|
/// use rhai::{Module, FnNamespace, FnAccess};
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-11-17 08:11:58 +01:00
|
|
|
/// let hash = module.set_raw_fn("double_or_not", FnNamespace::Internal, FnAccess::Public,
|
2020-07-07 16:59:23 +02:00
|
|
|
/// // Pass parameter types via a slice with TypeId's
|
2020-07-28 04:25:57 +02:00
|
|
|
/// &[std::any::TypeId::of::<i64>(), std::any::TypeId::of::<bool>()],
|
2020-07-07 16:59:23 +02:00
|
|
|
/// // Fixed closure signature
|
2020-10-18 11:08:57 +02:00
|
|
|
/// |context, args| {
|
2020-07-07 16:59:23 +02: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
|
|
|
|
/// let double = args[1].clone().cast::<bool>();
|
|
|
|
/// // Get a mutable reference to the first argument.
|
2020-07-27 06:30:09 +02:00
|
|
|
/// let mut x = args[0].write_lock::<i64>().unwrap();
|
2020-07-07 16:59:23 +02:00
|
|
|
///
|
|
|
|
/// let orig = *x;
|
|
|
|
///
|
|
|
|
/// if double {
|
|
|
|
/// *x *= 2; // the first argument can be mutated
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// Ok(orig) // return Result<T, Box<EvalAltResult>>
|
|
|
|
/// });
|
|
|
|
///
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-07-07 16:59:23 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-07-07 16:59:23 +02:00
|
|
|
pub fn set_raw_fn<T: Variant + Clone>(
|
2020-06-15 15:49:02 +02:00
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace: FnNamespace,
|
|
|
|
access: FnAccess,
|
2020-07-07 16:59:23 +02:00
|
|
|
arg_types: &[TypeId],
|
2020-10-19 13:11:55 +02:00
|
|
|
func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result<T, Box<EvalAltResult>>
|
2020-10-18 11:02:17 +02:00
|
|
|
+ SendSync
|
|
|
|
+ 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-11-02 04:04:45 +01:00
|
|
|
let f =
|
|
|
|
move |ctx: NativeCallContext, args: &mut FnCallArgs| func(ctx, args).map(Dynamic::from);
|
2020-11-17 05:23:53 +01:00
|
|
|
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace,
|
|
|
|
access,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
arg_types,
|
|
|
|
CallableFunction::from_method(Box::new(f)),
|
|
|
|
)
|
2020-06-15 15:49:02 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking no parameters into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-09 18:19:13 +02:00
|
|
|
/// let hash = module.set_fn_0("calc", || Ok(42_i64));
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-22 15:50:24 +02:00
|
|
|
pub fn set_fn_0<T: Variant + Clone>(
|
2020-05-05 11:51:40 +02:00
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_pure(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking one parameter into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-09 18:19:13 +02:00
|
|
|
/// let hash = module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-22 15:50:24 +02:00
|
|
|
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
2020-05-05 11:51:40 +02:00
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
|
2020-06-15 15:49:02 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_pure(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking one mutable parameter into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-11-17 08:11:58 +01:00
|
|
|
/// use rhai::{Module, FnNamespace};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-11-17 08:11:58 +01:00
|
|
|
/// let hash = module.set_fn_1_mut("calc", FnNamespace::Internal,
|
|
|
|
/// |x: &mut i64| { *x += 1; Ok(*x) }
|
|
|
|
/// );
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-22 15:50:24 +02:00
|
|
|
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
2020-05-05 11:51:40 +02:00
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace: FnNamespace,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-07-27 06:30:09 +02:00
|
|
|
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
|
2020-05-05 11:51:40 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_method(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-05-30 04:28:17 +02:00
|
|
|
/// Set a Rust getter function taking one mutable parameter, returning a hash key.
|
2020-11-17 08:11:58 +01:00
|
|
|
/// This function is automatically exposed to the global namespace.
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust getter function, it is replaced.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::Module;
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// let hash = module.set_getter_fn("value", |x: &mut i64| { Ok(*x) });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-30 04:28:17 +02:00
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-30 04:28:17 +02:00
|
|
|
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-11-17 08:11:58 +01:00
|
|
|
self.set_fn_1_mut(
|
|
|
|
crate::engine::make_getter(&name.into()),
|
|
|
|
FnNamespace::Global,
|
|
|
|
func,
|
|
|
|
)
|
2020-05-30 04:28:17 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking two parameters into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-05-30 04:28:17 +02:00
|
|
|
/// use rhai::{Module, ImmutableString};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-30 04:28:17 +02:00
|
|
|
/// let hash = module.set_fn_2("calc", |x: i64, y: ImmutableString| {
|
2020-05-06 13:45:17 +02:00
|
|
|
/// Ok(x + y.len() as i64)
|
2020-05-09 18:19:13 +02:00
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-22 15:50:24 +02:00
|
|
|
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
2020-05-05 11:51:40 +02:00
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let a = cast_arg::<A>(&mut args[0]);
|
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
2020-05-05 11:51:40 +02:00
|
|
|
|
2020-05-13 15:58:38 +02:00
|
|
|
func(a, b).map(Dynamic::from)
|
2020-05-05 11:51:40 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_pure(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking two parameters (the first one mutable) into the [`Module`],
|
2020-05-05 11:51:40 +02:00
|
|
|
/// returning a hash key.
|
|
|
|
///
|
2020-05-30 04:28:17 +02:00
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-11-17 08:11:58 +01:00
|
|
|
/// use rhai::{Module, FnNamespace, ImmutableString};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-11-17 08:11:58 +01:00
|
|
|
/// let hash = module.set_fn_2_mut("calc", FnNamespace::Internal,
|
|
|
|
/// |x: &mut i64, y: ImmutableString| {
|
|
|
|
/// *x += y.len() as i64;
|
|
|
|
/// Ok(*x)
|
|
|
|
/// }
|
|
|
|
/// );
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-22 15:50:24 +02:00
|
|
|
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
2020-05-05 11:51:40 +02:00
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace: FnNamespace,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
2020-08-11 07:46:09 +02:00
|
|
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
2020-05-05 11:51:40 +02:00
|
|
|
|
2020-08-11 07:46:09 +02:00
|
|
|
func(a, b).map(Dynamic::from)
|
2020-05-05 11:51:40 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_method(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`],
|
2020-05-30 04:28:17 +02:00
|
|
|
/// returning a hash key.
|
2020-11-17 08:11:58 +01:00
|
|
|
/// This function is automatically exposed to the global namespace.
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing setter Rust function, it is replaced.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// 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(())
|
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-30 04:28:17 +02:00
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-30 04:28:17 +02:00
|
|
|
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-11-17 08:11:58 +01:00
|
|
|
self.set_fn_2_mut(
|
|
|
|
crate::engine::make_setter(&name.into()),
|
|
|
|
FnNamespace::Global,
|
|
|
|
func,
|
|
|
|
)
|
2020-05-30 04:28:17 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`],
|
2020-05-30 04:28:17 +02:00
|
|
|
/// returning a hash key.
|
2020-11-17 08:11:58 +01:00
|
|
|
/// This function is automatically exposed to the global namespace.
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing setter Rust function, it is replaced.
|
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`] or [`Map`].
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-30 04:28:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::{Module, ImmutableString};
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-06-06 07:06:00 +02:00
|
|
|
/// let hash = module.set_indexer_get_fn(|x: &mut i64, y: ImmutableString| {
|
2020-05-30 04:28:17 +02:00
|
|
|
/// Ok(*x + y.len() as i64)
|
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-30 04:28:17 +02:00
|
|
|
/// ```
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-06-06 07:06:00 +02:00
|
|
|
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
2020-05-30 04:28:17 +02:00
|
|
|
&mut self,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<A>() == TypeId::of::<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-11-17 08:11:58 +01:00
|
|
|
self.set_fn_2_mut(crate::engine::FN_IDX_GET, FnNamespace::Global, func)
|
2020-05-30 04:28:17 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking three parameters into the [`Module`], returning a hash key.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-05-30 04:28:17 +02:00
|
|
|
/// use rhai::{Module, ImmutableString};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-30 04:28:17 +02:00
|
|
|
/// let hash = module.set_fn_3("calc", |x: i64, y: ImmutableString, z: i64| {
|
2020-05-06 13:45:17 +02:00
|
|
|
/// Ok(x + y.len() as i64 + z)
|
2020-05-09 18:19:13 +02:00
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-05 11:51:40 +02:00
|
|
|
pub fn set_fn_3<
|
|
|
|
A: Variant + Clone,
|
|
|
|
B: Variant + Clone,
|
|
|
|
C: Variant + Clone,
|
2020-05-13 13:21:42 +02:00
|
|
|
T: Variant + Clone,
|
2020-05-05 11:51:40 +02:00
|
|
|
>(
|
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let a = cast_arg::<A>(&mut args[0]);
|
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
|
|
|
let c = cast_arg::<C>(&mut args[2]);
|
2020-05-05 11:51:40 +02:00
|
|
|
|
2020-05-13 15:58:38 +02:00
|
|
|
func(a, b, c).map(Dynamic::from)
|
2020-05-05 11:51:40 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_pure(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking three parameters (the first one mutable) into the [`Module`],
|
2020-05-05 11:51:40 +02:00
|
|
|
/// returning a hash key.
|
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-11-17 08:11:58 +01:00
|
|
|
/// use rhai::{Module, FnNamespace, ImmutableString};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-11-17 08:11:58 +01:00
|
|
|
/// let hash = module.set_fn_3_mut("calc", FnNamespace::Internal,
|
|
|
|
/// |x: &mut i64, y: ImmutableString, z: i64| {
|
|
|
|
/// *x += y.len() as i64 + z;
|
|
|
|
/// Ok(*x)
|
|
|
|
/// }
|
|
|
|
/// );
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-06 13:45:17 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-05 11:51:40 +02:00
|
|
|
pub fn set_fn_3_mut<
|
|
|
|
A: Variant + Clone,
|
|
|
|
B: Variant + Clone,
|
|
|
|
C: Variant + Clone,
|
2020-05-13 13:21:42 +02:00
|
|
|
T: Variant + Clone,
|
2020-05-05 11:51:40 +02:00
|
|
|
>(
|
|
|
|
&mut self,
|
2020-05-22 15:50:24 +02:00
|
|
|
name: impl Into<String>,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace: FnNamespace,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let b = cast_arg::<B>(&mut args[2]);
|
|
|
|
let c = cast_arg::<C>(&mut args[3]);
|
2020-08-11 07:46:09 +02:00
|
|
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
2020-05-05 11:51:40 +02:00
|
|
|
|
2020-08-11 07:46:09 +02:00
|
|
|
func(a, b, c).map(Dynamic::from)
|
2020-05-05 11:51:40 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_method(Box::new(f)),
|
|
|
|
)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`],
|
2020-06-06 07:06:00 +02:00
|
|
|
/// returning a hash key.
|
2020-11-17 08:11:58 +01:00
|
|
|
/// This function is automatically exposed to the global namespace.
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`] or [`Map`].
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-06-06 07:06:00 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use rhai::{Module, ImmutableString};
|
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
|
|
|
/// let hash = module.set_indexer_set_fn(|x: &mut i64, y: ImmutableString, value: i64| {
|
|
|
|
/// *x = y.len() as i64 + value;
|
|
|
|
/// Ok(())
|
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-06-06 07:06:00 +02:00
|
|
|
/// ```
|
2020-07-26 09:53:22 +02:00
|
|
|
#[cfg(not(feature = "no_index"))]
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-07-24 17:16:54 +02:00
|
|
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
2020-06-06 07:06:00 +02:00
|
|
|
&mut self,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-09-22 11:57:56 +02:00
|
|
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
|
|
|
panic!("Cannot register indexer for arrays.");
|
|
|
|
}
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
|
|
|
if TypeId::of::<A>() == TypeId::of::<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-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
|
|
|
let c = cast_arg::<C>(&mut args[2]);
|
2020-08-11 07:46:09 +02:00
|
|
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
2020-06-06 07:06:00 +02:00
|
|
|
|
2020-08-11 07:46:09 +02:00
|
|
|
func(a, b, c).map(Dynamic::from)
|
2020-06-06 07:06:00 +02:00
|
|
|
};
|
2020-07-24 17:16:54 +02:00
|
|
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
2020-06-06 07:06:00 +02:00
|
|
|
self.set_fn(
|
2020-11-16 09:28:04 +01:00
|
|
|
crate::engine::FN_IDX_SET,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-07-07 16:59:23 +02:00
|
|
|
&arg_types,
|
2020-09-25 12:07:39 +02:00
|
|
|
CallableFunction::from_method(Box::new(f)),
|
2020-06-06 07:06:00 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-07-24 17:16:54 +02:00
|
|
|
/// Set a pair of Rust index getter and setter functions, returning both hash keys.
|
2020-11-20 09:52:28 +01: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 17:16:54 +02:00
|
|
|
///
|
|
|
|
/// If there are similar existing Rust functions, they are replaced.
|
|
|
|
///
|
2020-09-22 11:57:56 +02:00
|
|
|
/// # Panics
|
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Panics if the type is [`Array`] or [`Map`].
|
2020-09-22 11:57:56 +02:00
|
|
|
/// Indexers for arrays, object maps and strings cannot be registered.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-07-24 17:16:54 +02: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| {
|
|
|
|
/// *x = y.len() as i64 + value;
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// );
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash_get, true));
|
|
|
|
/// assert!(module.contains_fn(hash_set, true));
|
2020-07-24 17:16:54 +02:00
|
|
|
/// ```
|
2020-07-26 09:53:22 +02:00
|
|
|
#[cfg(not(feature = "no_index"))]
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-07-24 17:16:54 +02:00
|
|
|
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
|
|
|
&mut self,
|
2020-10-18 11:02:17 +02:00
|
|
|
getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
|
|
|
setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> (NonZeroU64, NonZeroU64) {
|
2020-07-24 17:16:54 +02:00
|
|
|
(
|
|
|
|
self.set_indexer_get_fn(getter),
|
|
|
|
self.set_indexer_set_fn(setter),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking four parameters into the [`Module`], returning a hash key.
|
2020-05-28 08:07:34 +02:00
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-28 08:07:34 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-05-30 04:28:17 +02:00
|
|
|
/// use rhai::{Module, ImmutableString};
|
2020-05-28 08:07:34 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-05-30 04:28:17 +02:00
|
|
|
/// let hash = module.set_fn_4("calc", |x: i64, y: ImmutableString, z: i64, _w: ()| {
|
2020-05-28 08:07:34 +02:00
|
|
|
/// Ok(x + y.len() as i64 + z)
|
|
|
|
/// });
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-28 08:07:34 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-28 08:07:34 +02:00
|
|
|
pub fn set_fn_4<
|
|
|
|
A: Variant + Clone,
|
|
|
|
B: Variant + Clone,
|
|
|
|
C: Variant + Clone,
|
|
|
|
D: Variant + Clone,
|
|
|
|
T: Variant + Clone,
|
|
|
|
>(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let a = cast_arg::<A>(&mut args[0]);
|
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
|
|
|
let c = cast_arg::<C>(&mut args[2]);
|
|
|
|
let d = cast_arg::<D>(&mut args[3]);
|
2020-05-28 08:07:34 +02:00
|
|
|
|
|
|
|
func(a, b, c, d).map(Dynamic::from)
|
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [
|
2020-05-28 08:07:34 +02:00
|
|
|
TypeId::of::<A>(),
|
|
|
|
TypeId::of::<B>(),
|
|
|
|
TypeId::of::<C>(),
|
|
|
|
TypeId::of::<D>(),
|
|
|
|
];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
FnNamespace::Internal,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_pure(Box::new(f)),
|
|
|
|
)
|
2020-05-28 08:07:34 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a Rust function taking four parameters (the first one mutable) into the [`Module`],
|
2020-05-28 08:07:34 +02:00
|
|
|
/// returning a hash key.
|
|
|
|
///
|
|
|
|
/// If there is a similar existing Rust function, it is replaced.
|
|
|
|
///
|
2020-11-22 15:15:17 +01:00
|
|
|
/// # Function Metadata
|
|
|
|
///
|
|
|
|
/// No metadata for the function is registered. Use `update_fn_metadata` to add metadata.
|
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-28 08:07:34 +02:00
|
|
|
///
|
|
|
|
/// ```
|
2020-11-17 08:11:58 +01:00
|
|
|
/// use rhai::{Module, FnNamespace, ImmutableString};
|
2020-05-28 08:07:34 +02:00
|
|
|
///
|
|
|
|
/// let mut module = Module::new();
|
2020-11-17 08:11:58 +01:00
|
|
|
/// let hash = module.set_fn_4_mut("calc", FnNamespace::Internal,
|
|
|
|
/// |x: &mut i64, y: ImmutableString, z: i64, _w: ()| {
|
|
|
|
/// *x += y.len() as i64 + z;
|
|
|
|
/// Ok(*x)
|
|
|
|
/// }
|
|
|
|
/// );
|
2020-07-27 12:10:45 +02:00
|
|
|
/// assert!(module.contains_fn(hash, true));
|
2020-05-28 08:07:34 +02:00
|
|
|
/// ```
|
2021-01-03 06:29:42 +01:00
|
|
|
#[inline(always)]
|
2020-05-28 08:07:34 +02:00
|
|
|
pub fn set_fn_4_mut<
|
|
|
|
A: Variant + Clone,
|
|
|
|
B: Variant + Clone,
|
|
|
|
C: Variant + Clone,
|
|
|
|
D: Variant + Clone,
|
|
|
|
T: Variant + Clone,
|
|
|
|
>(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace: FnNamespace,
|
2020-10-18 11:02:17 +02:00
|
|
|
func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
2020-12-24 09:32:43 +01:00
|
|
|
) -> NonZeroU64 {
|
2020-10-18 11:02:17 +02:00
|
|
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
2020-09-19 12:12:23 +02:00
|
|
|
let b = cast_arg::<B>(&mut args[1]);
|
|
|
|
let c = cast_arg::<C>(&mut args[2]);
|
|
|
|
let d = cast_arg::<D>(&mut args[3]);
|
2020-08-11 07:46:09 +02:00
|
|
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
2020-05-28 08:07:34 +02:00
|
|
|
|
2020-08-11 07:46:09 +02:00
|
|
|
func(a, b, c, d).map(Dynamic::from)
|
2020-05-28 08:07:34 +02:00
|
|
|
};
|
2020-07-07 16:59:23 +02:00
|
|
|
let arg_types = [
|
2020-05-28 08:07:34 +02:00
|
|
|
TypeId::of::<A>(),
|
|
|
|
TypeId::of::<B>(),
|
|
|
|
TypeId::of::<C>(),
|
2020-09-15 05:03:46 +02:00
|
|
|
TypeId::of::<D>(),
|
2020-05-28 08:07:34 +02:00
|
|
|
];
|
2020-09-25 12:07:39 +02:00
|
|
|
self.set_fn(
|
|
|
|
name,
|
2020-11-17 08:11:58 +01:00
|
|
|
namespace,
|
2020-10-01 17:31:27 +02:00
|
|
|
FnAccess::Public,
|
2020-11-22 10:21:34 +01:00
|
|
|
None,
|
2020-09-25 12:07:39 +02:00
|
|
|
&arg_types,
|
|
|
|
CallableFunction::from_method(Box::new(f)),
|
|
|
|
)
|
2020-05-28 08:07:34 +02:00
|
|
|
}
|
|
|
|
|
2020-05-05 11:51:40 +02:00
|
|
|
/// Get a Rust function.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated by the function [`calc_native_fn_hash`][crate::calc_native_fn_hash].
|
2020-05-05 11:51:40 +02:00
|
|
|
/// It is also returned by the `set_fn_XXX` calls.
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub(crate) fn get_fn(
|
|
|
|
&self,
|
|
|
|
hash_fn: NonZeroU64,
|
|
|
|
public_only: bool,
|
|
|
|
) -> Option<&CallableFunction> {
|
|
|
|
self.functions
|
|
|
|
.get(&hash_fn)
|
|
|
|
.and_then(|FuncInfo { access, func, .. }| match access {
|
|
|
|
_ if !public_only => Some(func),
|
|
|
|
FnAccess::Public => Some(func),
|
|
|
|
FnAccess::Private => None,
|
|
|
|
})
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Does the particular namespace-qualified function exist in the [`Module`]?
|
2020-11-16 07:07:48 +01:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated by the function
|
|
|
|
/// [`calc_native_fn_hash`][crate::calc_native_fn_hash] and must match
|
2020-11-20 09:52:28 +01:00
|
|
|
/// the hash calculated by [`build_index`][Module::build_index].
|
2020-12-24 09:32:43 +01:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn contains_qualified_fn(&self, hash_fn: NonZeroU64) -> bool {
|
|
|
|
self.all_functions.contains_key(&hash_fn)
|
2020-11-16 07:07:48 +01:00
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
/// Get a namespace-qualified function.
|
2020-05-05 11:51:40 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// The [`NonZeroU64`] hash is calculated by the function
|
|
|
|
/// [`calc_native_fn_hash`][crate::calc_native_fn_hash] and must match
|
2020-11-20 09:52:28 +01:00
|
|
|
/// the hash calculated by [`build_index`][Module::build_index].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-12-24 09:32:43 +01:00
|
|
|
pub(crate) fn get_qualified_fn(
|
|
|
|
&self,
|
|
|
|
hash_qualified_fn: NonZeroU64,
|
|
|
|
) -> Option<&CallableFunction> {
|
|
|
|
self.all_functions.get(&hash_qualified_fn)
|
2020-05-05 11:51:40 +02:00
|
|
|
}
|
2020-05-05 17:57:25 +02:00
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Combine another [`Module`] into this [`Module`].
|
|
|
|
/// The other [`Module`] is _consumed_ to merge into this [`Module`].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline]
|
2020-08-14 18:04:10 +02:00
|
|
|
pub fn combine(&mut self, other: Self) -> &mut Self {
|
2020-10-24 18:39:47 +02:00
|
|
|
self.modules.extend(other.modules.into_iter());
|
|
|
|
self.variables.extend(other.variables.into_iter());
|
|
|
|
self.functions.extend(other.functions.into_iter());
|
|
|
|
self.type_iterators.extend(other.type_iterators.into_iter());
|
2020-08-21 15:48:45 +02:00
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
2020-11-16 07:07:48 +01:00
|
|
|
self.all_type_iterators.clear();
|
2020-08-21 15:48:45 +02:00
|
|
|
self.indexed = false;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01: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 16:25:50 +02:00
|
|
|
#[inline]
|
2020-08-21 15:48:45 +02:00
|
|
|
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
|
2020-10-24 18:39:47 +02:00
|
|
|
other.modules.into_iter().for_each(|(_, m)| {
|
2020-11-09 15:44:20 +01:00
|
|
|
self.combine_flatten(shared_take_or_clone(m));
|
2020-10-24 18:39:47 +02:00
|
|
|
});
|
|
|
|
self.variables.extend(other.variables.into_iter());
|
|
|
|
self.functions.extend(other.functions.into_iter());
|
|
|
|
self.type_iterators.extend(other.type_iterators.into_iter());
|
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
2020-11-16 07:07:48 +01:00
|
|
|
self.all_type_iterators.clear();
|
2020-10-24 18:39:47 +02:00
|
|
|
self.indexed = false;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Polyfill this [`Module`] with another [`Module`].
|
|
|
|
/// Only items not existing in this [`Module`] are added.
|
2020-10-24 18:39:47 +02:00
|
|
|
#[inline]
|
|
|
|
pub fn fill_with(&mut self, other: &Self) -> &mut Self {
|
|
|
|
other.modules.iter().for_each(|(k, v)| {
|
|
|
|
if !self.modules.contains_key(k) {
|
|
|
|
self.modules.insert(k.clone(), v.clone());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
other.variables.iter().for_each(|(k, v)| {
|
|
|
|
if !self.variables.contains_key(k) {
|
|
|
|
self.variables.insert(k.clone(), v.clone());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
other.functions.iter().for_each(|(&k, v)| {
|
|
|
|
self.functions.entry(k).or_insert_with(|| v.clone());
|
|
|
|
});
|
|
|
|
other.type_iterators.iter().for_each(|(&k, &v)| {
|
|
|
|
self.type_iterators.entry(k).or_insert(v);
|
|
|
|
});
|
2020-08-14 18:04:10 +02:00
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
2020-11-16 07:07:48 +01:00
|
|
|
self.all_type_iterators.clear();
|
2020-08-14 18:04:10 +02:00
|
|
|
self.indexed = false;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Merge another [`Module`] into this [`Module`].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn merge(&mut self, other: &Self) -> &mut Self {
|
2020-11-17 05:23:53 +01:00
|
|
|
self.merge_filtered(other, &mut |_, _, _, _, _| true)
|
2020-06-30 12:34:58 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Merge another [`Module`] into this [`Module`] based on a filter predicate.
|
2020-06-30 12:34:58 +02:00
|
|
|
pub(crate) fn merge_filtered(
|
|
|
|
&mut self,
|
|
|
|
other: &Self,
|
2020-11-17 05:23:53 +01:00
|
|
|
mut _filter: &mut impl FnMut(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
2020-07-12 05:46:53 +02:00
|
|
|
) -> &mut Self {
|
2020-08-21 15:48:45 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-24 18:39:47 +02:00
|
|
|
other.modules.iter().for_each(|(k, v)| {
|
|
|
|
let mut m = Self::new();
|
|
|
|
m.merge_filtered(v, _filter);
|
2020-12-11 05:57:07 +01:00
|
|
|
self.set_sub_module(k.clone(), m);
|
2020-10-24 18:39:47 +02:00
|
|
|
});
|
2020-08-21 15:48:45 +02:00
|
|
|
#[cfg(feature = "no_function")]
|
2020-10-24 18:39:47 +02:00
|
|
|
self.modules
|
|
|
|
.extend(other.modules.iter().map(|(k, v)| (k.clone(), v.clone())));
|
|
|
|
|
|
|
|
self.variables
|
|
|
|
.extend(other.variables.iter().map(|(k, v)| (k.clone(), v.clone())));
|
|
|
|
self.functions.extend(
|
|
|
|
other
|
|
|
|
.functions
|
|
|
|
.iter()
|
2020-11-17 05:23:53 +01:00
|
|
|
.filter(
|
|
|
|
|(
|
|
|
|
_,
|
|
|
|
FuncInfo {
|
|
|
|
namespace,
|
|
|
|
access,
|
|
|
|
name,
|
|
|
|
params,
|
|
|
|
func,
|
|
|
|
..
|
|
|
|
},
|
|
|
|
)| {
|
|
|
|
_filter(
|
|
|
|
*namespace,
|
|
|
|
*access,
|
|
|
|
func.is_script(),
|
|
|
|
name.as_str(),
|
|
|
|
*params,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
2020-10-24 18:39:47 +02:00
|
|
|
.map(|(&k, v)| (k, v.clone())),
|
|
|
|
);
|
2020-06-30 12:34:58 +02:00
|
|
|
|
2020-10-24 18:39:47 +02:00
|
|
|
self.type_iterators.extend(other.type_iterators.iter());
|
2020-06-30 12:34:58 +02:00
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
2020-11-16 07:07:48 +01:00
|
|
|
self.all_type_iterators.clear();
|
2020-06-30 12:34:58 +02:00
|
|
|
self.indexed = false;
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-06-30 12:34:58 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 05:23:53 +01:00
|
|
|
/// Filter out the functions, retaining only some script-defined functions based on a filter predicate.
|
2020-07-04 10:21:15 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline]
|
2020-11-17 05:23:53 +01:00
|
|
|
pub(crate) fn retain_script_functions(
|
2020-07-12 05:46:53 +02:00
|
|
|
&mut self,
|
2020-11-17 05:23:53 +01:00
|
|
|
mut filter: impl FnMut(FnNamespace, FnAccess, &str, usize) -> bool,
|
2020-07-12 05:46:53 +02:00
|
|
|
) -> &mut Self {
|
2020-11-17 05:23:53 +01:00
|
|
|
self.functions.retain(
|
|
|
|
|_,
|
|
|
|
FuncInfo {
|
|
|
|
namespace,
|
|
|
|
access,
|
|
|
|
name,
|
|
|
|
params,
|
|
|
|
func,
|
|
|
|
..
|
|
|
|
}| {
|
|
|
|
if func.is_script() {
|
|
|
|
filter(*namespace, *access, name.as_str(), *params)
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
2020-06-30 12:34:58 +02:00
|
|
|
|
|
|
|
self.all_functions.clear();
|
|
|
|
self.all_variables.clear();
|
2020-11-16 07:07:48 +01:00
|
|
|
self.all_type_iterators.clear();
|
2020-06-30 12:34:58 +02:00
|
|
|
self.indexed = false;
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-06-05 09:14:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get the number of variables, functions and type iterators in the [`Module`].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-10-05 15:52:39 +02:00
|
|
|
pub fn count(&self) -> (usize, usize, usize) {
|
|
|
|
(
|
|
|
|
self.variables.len(),
|
2020-11-09 15:44:20 +01:00
|
|
|
self.functions.len(),
|
|
|
|
self.type_iterators.len(),
|
2020-10-05 15:52:39 +02:00
|
|
|
)
|
2020-06-05 09:14:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator to the sub-modules in the [`Module`].
|
2020-11-23 12:11:32 +01:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn iter_sub_modules(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
|
|
|
|
self.modules.iter().map(|(k, m)| (k.as_str(), m.clone()))
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator to the variables in the [`Module`].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-23 12:11:32 +01:00
|
|
|
pub fn iter_var(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
|
|
|
|
self.variables.iter().map(|(k, v)| (k.as_str(), v))
|
2020-06-05 09:14:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator to the functions in the [`Module`].
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2021-01-18 03:56:42 +01:00
|
|
|
#[allow(dead_code)]
|
2020-09-25 12:07:39 +02:00
|
|
|
pub(crate) fn iter_fn(&self) -> impl Iterator<Item = &FuncInfo> {
|
2020-06-05 09:14:42 +02:00
|
|
|
self.functions.values()
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator over all script-defined functions in the [`Module`].
|
2020-10-05 15:52:39 +02:00
|
|
|
///
|
|
|
|
/// Function metadata includes:
|
2020-11-20 09:52:28 +01: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 02:36:06 +01:00
|
|
|
/// 5) Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
2020-07-04 10:21:15 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-10-05 15:52:39 +02:00
|
|
|
pub(crate) fn iter_script_fn<'a>(
|
2020-10-02 17:14:33 +02:00
|
|
|
&'a self,
|
2020-11-25 02:36:06 +01:00
|
|
|
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> + 'a {
|
2020-11-17 05:23:53 +01:00
|
|
|
self.functions.values().filter(|f| f.func.is_script()).map(
|
|
|
|
|FuncInfo {
|
|
|
|
namespace,
|
|
|
|
access,
|
|
|
|
name,
|
|
|
|
params,
|
|
|
|
func,
|
|
|
|
..
|
|
|
|
}| {
|
|
|
|
(
|
|
|
|
*namespace,
|
|
|
|
*access,
|
|
|
|
name.as_str(),
|
|
|
|
*params,
|
2020-11-25 02:36:06 +01:00
|
|
|
func.get_fn_def(),
|
2020-11-17 05:23:53 +01:00
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
2020-09-24 10:10:25 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator over all script-defined functions in the [`Module`].
|
2020-10-05 15:52:39 +02:00
|
|
|
///
|
|
|
|
/// Function metadata includes:
|
2020-11-20 09:52:28 +01: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 15:52:39 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
#[cfg(not(feature = "internals"))]
|
2020-10-08 16:25:50 +02:00
|
|
|
#[inline(always)]
|
2020-11-17 05:23:53 +01:00
|
|
|
pub fn iter_script_fn_info(
|
|
|
|
&self,
|
|
|
|
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> {
|
2020-11-04 07:37:46 +01:00
|
|
|
self.functions.values().filter(|f| f.func.is_script()).map(
|
|
|
|
|FuncInfo {
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace,
|
2020-11-04 07:37:46 +01:00
|
|
|
access,
|
|
|
|
params,
|
|
|
|
..
|
2020-11-17 05:23:53 +01:00
|
|
|
}| (*namespace, *access, name.as_str(), *params),
|
2020-11-04 07:37:46 +01:00
|
|
|
)
|
2020-10-05 15:52:39 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Get an iterator over all script-defined functions in the [`Module`].
|
2020-10-05 15:52:39 +02:00
|
|
|
///
|
|
|
|
/// Function metadata includes:
|
2020-11-20 09:52:28 +01: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 02:36:06 +01:00
|
|
|
/// 5) _(INTERNALS)_ Shared reference to function definition [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
2020-11-20 09:52:28 +01:00
|
|
|
/// Exported under the `internals` feature only.
|
2020-10-05 15:52:39 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
#[cfg(feature = "internals")]
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn iter_script_fn_info(
|
|
|
|
&self,
|
2020-11-25 02:36:06 +01:00
|
|
|
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize, &ScriptFnDef)> {
|
2020-10-05 15:52:39 +02:00
|
|
|
self.iter_script_fn()
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions
|
2020-10-03 05:42:54 +02:00
|
|
|
/// to cross-call each other. Functions in the global namespace, plus all functions
|
2021-01-02 16:30:10 +01:00
|
|
|
/// defined in the [`Module`], are _merged_ into a _unified_ namespace before each call.
|
2020-10-03 05:42:54 +02:00
|
|
|
/// Therefore, all functions will be found.
|
2020-09-25 12:07:39 +02:00
|
|
|
///
|
2020-10-27 04:30:38 +01:00
|
|
|
/// # Example
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
2020-05-08 16:38:56 +02:00
|
|
|
/// use rhai::{Engine, Module, Scope};
|
2020-05-06 13:45:17 +02:00
|
|
|
///
|
|
|
|
/// let engine = Engine::new();
|
2020-05-08 16:38:56 +02:00
|
|
|
/// let ast = engine.compile("let answer = 42; export answer;")?;
|
2020-10-03 05:42:54 +02:00
|
|
|
/// let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
|
2020-05-06 13:45:17 +02:00
|
|
|
/// assert!(module.contains_var("answer"));
|
|
|
|
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
2020-05-13 13:21:42 +02:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-10-18 11:02:17 +02:00
|
|
|
pub fn eval_ast_as_new(
|
2020-11-16 09:28:04 +01:00
|
|
|
mut scope: crate::Scope,
|
|
|
|
ast: &crate::AST,
|
|
|
|
engine: &crate::Engine,
|
2020-10-18 11:02:17 +02:00
|
|
|
) -> Result<Self, Box<EvalAltResult>> {
|
2020-12-26 06:05:57 +01:00
|
|
|
let mut mods: crate::engine::Imports = (&engine.global_sub_modules).into();
|
2020-11-15 16:14:16 +01:00
|
|
|
let orig_mods_len = mods.len();
|
2020-06-27 17:56:24 +02:00
|
|
|
|
2020-05-06 13:45:17 +02:00
|
|
|
// Run the script
|
2020-12-29 05:29:45 +01:00
|
|
|
engine.eval_ast_with_scope_raw(&mut scope, &mut mods, &ast, 0)?;
|
2020-05-06 13:45:17 +02:00
|
|
|
|
|
|
|
// Create new module
|
|
|
|
let mut module = Module::new();
|
|
|
|
|
2020-12-08 15:47:38 +01:00
|
|
|
scope.into_iter().for_each(|(_, value, mut aliases)| {
|
2020-11-01 15:46:46 +01:00
|
|
|
// Variables with an alias left in the scope become module variables
|
2020-11-09 07:38:33 +01:00
|
|
|
if aliases.len() > 1 {
|
|
|
|
aliases.into_iter().for_each(|alias| {
|
|
|
|
module.variables.insert(alias, value.clone());
|
|
|
|
});
|
|
|
|
} else if aliases.len() == 1 {
|
|
|
|
module.variables.insert(aliases.pop().unwrap(), value);
|
2020-11-01 15:46:46 +01:00
|
|
|
}
|
|
|
|
});
|
2020-06-27 17:56:24 +02:00
|
|
|
|
2020-11-15 16:14:16 +01:00
|
|
|
// Extra modules left in the scope become sub-modules
|
2020-11-16 09:28:04 +01:00
|
|
|
let mut func_mods: crate::engine::Imports = Default::default();
|
2020-11-15 16:14:16 +01:00
|
|
|
|
2020-11-17 05:23:53 +01:00
|
|
|
mods.into_iter().skip(orig_mods_len).for_each(|(alias, m)| {
|
|
|
|
func_mods.push(alias.clone(), m.clone());
|
|
|
|
module.set_sub_module(alias, m);
|
|
|
|
});
|
2020-05-06 13:45:17 +02:00
|
|
|
|
2020-10-13 03:38:14 +02:00
|
|
|
// Non-private functions defined become module functions
|
2020-09-25 12:07:39 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-10-03 05:42:54 +02:00
|
|
|
{
|
2020-11-25 02:36:06 +01:00
|
|
|
ast.lib()
|
|
|
|
.functions
|
|
|
|
.values()
|
|
|
|
.filter(|FuncInfo { access, func, .. }| !access.is_private() && func.is_script())
|
|
|
|
.for_each(|FuncInfo { func, .. }| {
|
2020-10-13 03:38:14 +02:00
|
|
|
// Encapsulate AST environment
|
2020-11-25 02:36:06 +01:00
|
|
|
let mut func = func.get_fn_def().clone();
|
2020-11-19 03:52:45 +01:00
|
|
|
func.lib = Some(ast.shared_lib());
|
2020-11-15 16:14:16 +01:00
|
|
|
func.mods = func_mods.clone();
|
2020-11-25 02:36:06 +01:00
|
|
|
module.set_script_fn(func);
|
2020-10-01 17:31:27 +02:00
|
|
|
});
|
2020-09-25 12:07:39 +02:00
|
|
|
}
|
2020-05-06 13:45:17 +02:00
|
|
|
|
2020-12-21 15:04:46 +01:00
|
|
|
module.set_id(ast.clone_source());
|
2020-11-21 15:18:32 +01:00
|
|
|
module.build_index();
|
|
|
|
|
2020-05-06 13:45:17 +02:00
|
|
|
Ok(module)
|
|
|
|
}
|
2020-05-07 18:19:08 +02:00
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Scan through all the sub-modules in the [`Module`] and build a hash index of all
|
2020-11-08 07:29:54 +01:00
|
|
|
/// variables and functions as one flattened namespace.
|
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// If the [`Module`] is already indexed, this method has no effect.
|
2020-11-21 15:18:32 +01:00
|
|
|
pub fn build_index(&mut self) -> &mut Self {
|
2020-05-07 18:19:08 +02:00
|
|
|
// Collect a particular module.
|
2020-05-09 04:00:59 +02:00
|
|
|
fn index_module<'a>(
|
2020-05-17 16:19:49 +02:00
|
|
|
module: &'a Module,
|
2020-05-09 04:00:59 +02:00
|
|
|
qualifiers: &mut Vec<&'a str>,
|
2020-12-24 09:32:43 +01:00
|
|
|
variables: &mut HashMap<NonZeroU64, Dynamic, StraightHasherBuilder>,
|
|
|
|
functions: &mut HashMap<NonZeroU64, CallableFunction, StraightHasherBuilder>,
|
2020-11-16 07:07:48 +01:00
|
|
|
type_iterators: &mut HashMap<TypeId, IteratorFn>,
|
2020-05-07 18:19:08 +02:00
|
|
|
) {
|
2020-10-01 17:31:27 +02:00
|
|
|
module.modules.iter().for_each(|(name, m)| {
|
2020-05-09 04:00:59 +02:00
|
|
|
// Index all the sub-modules first.
|
|
|
|
qualifiers.push(name);
|
2020-11-16 07:07:48 +01:00
|
|
|
index_module(m, qualifiers, variables, functions, type_iterators);
|
2020-05-09 04:00:59 +02:00
|
|
|
qualifiers.pop();
|
2020-10-01 17:31:27 +02:00
|
|
|
});
|
2020-05-07 18:19:08 +02:00
|
|
|
|
2020-05-09 04:00:59 +02:00
|
|
|
// Index all variables
|
2020-10-01 17:31:27 +02:00
|
|
|
module.variables.iter().for_each(|(var_name, value)| {
|
2020-05-09 04:00:59 +02:00
|
|
|
// Qualifiers + variable name
|
2020-11-16 09:28:04 +01:00
|
|
|
let hash_var =
|
2020-12-24 09:32:43 +01:00
|
|
|
crate::calc_script_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0).unwrap();
|
2020-11-16 07:07:48 +01:00
|
|
|
variables.insert(hash_var, value.clone());
|
|
|
|
});
|
|
|
|
|
|
|
|
// Index type iterators
|
|
|
|
module.type_iterators.iter().for_each(|(&type_id, func)| {
|
|
|
|
type_iterators.insert(type_id, func.clone());
|
2020-10-01 17:31:27 +02:00
|
|
|
});
|
2020-11-16 07:07:48 +01:00
|
|
|
|
2020-05-09 04:00:59 +02:00
|
|
|
// Index all Rust functions
|
2020-10-01 17:31:27 +02:00
|
|
|
module
|
|
|
|
.functions
|
|
|
|
.iter()
|
2020-11-04 07:37:46 +01:00
|
|
|
.filter(|(_, FuncInfo { access, .. })| access.is_public())
|
|
|
|
.for_each(
|
|
|
|
|(
|
2020-11-16 07:07:48 +01:00
|
|
|
&hash,
|
2020-11-04 07:37:46 +01:00
|
|
|
FuncInfo {
|
|
|
|
name,
|
2020-11-17 05:23:53 +01:00
|
|
|
namespace,
|
2020-11-04 07:37:46 +01:00
|
|
|
params,
|
2020-12-23 16:29:19 +01:00
|
|
|
param_types,
|
2020-11-04 07:37:46 +01:00
|
|
|
func,
|
|
|
|
..
|
|
|
|
},
|
|
|
|
)| {
|
2020-11-19 03:14:43 +01:00
|
|
|
// Flatten all functions with global namespace
|
2020-11-17 05:23:53 +01:00
|
|
|
if namespace.is_global() {
|
2020-11-16 07:07:48 +01:00
|
|
|
functions.insert(hash, func.clone());
|
|
|
|
}
|
|
|
|
|
2020-11-17 05:23:53 +01:00
|
|
|
// Qualifiers + function name + number of arguments.
|
|
|
|
let hash_qualified_script =
|
2020-12-24 09:32:43 +01:00
|
|
|
crate::calc_script_fn_hash(qualifiers.iter().cloned(), name, *params)
|
|
|
|
.unwrap();
|
2020-11-17 05:23:53 +01:00
|
|
|
|
2020-12-23 16:29:19 +01:00
|
|
|
if !func.is_script() {
|
2020-11-04 07:37:46 +01:00
|
|
|
assert_eq!(*params, param_types.len());
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
// Namespace-qualified Rust functions are indexed in two steps:
|
2020-11-04 07:37:46 +01:00
|
|
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
|
|
|
// i.e. qualifiers + function name + number of arguments.
|
|
|
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
2020-11-20 09:52:28 +01:00
|
|
|
// and the actual list of argument [`TypeId`]'.s
|
2020-11-16 09:28:04 +01:00
|
|
|
let hash_fn_args = crate::calc_native_fn_hash(
|
|
|
|
empty(),
|
|
|
|
"",
|
|
|
|
param_types.iter().cloned(),
|
2020-12-24 09:32:43 +01:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-24 11:43:04 +01:00
|
|
|
// 3) The two hashes are combined.
|
2020-12-24 09:32:43 +01:00
|
|
|
let hash_qualified_fn =
|
2020-12-24 11:43:04 +01:00
|
|
|
combine_hashes(hash_qualified_script, hash_fn_args);
|
2020-11-04 07:37:46 +01:00
|
|
|
|
2020-11-16 07:07:48 +01:00
|
|
|
functions.insert(hash_qualified_fn, func.clone());
|
2020-11-04 07:37:46 +01:00
|
|
|
} else if cfg!(not(feature = "no_function")) {
|
2020-11-16 07:07:48 +01:00
|
|
|
functions.insert(hash_qualified_script, func.clone());
|
2020-11-04 07:37:46 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
2020-06-27 17:56:24 +02:00
|
|
|
}
|
|
|
|
|
2020-10-01 17:31:27 +02:00
|
|
|
if !self.indexed {
|
2020-11-15 05:07:35 +01:00
|
|
|
let mut qualifiers = Vec::with_capacity(4);
|
2020-11-16 07:07:48 +01:00
|
|
|
let mut variables = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
|
|
|
|
let mut functions = HashMap::with_capacity_and_hasher(256, StraightHasherBuilder);
|
|
|
|
let mut type_iterators = HashMap::with_capacity(16);
|
2020-07-26 09:53:22 +02:00
|
|
|
|
2020-10-01 17:31:27 +02:00
|
|
|
qualifiers.push("root");
|
2020-05-19 13:03:06 +02:00
|
|
|
|
2020-11-16 07:07:48 +01:00
|
|
|
index_module(
|
|
|
|
self,
|
|
|
|
&mut qualifiers,
|
|
|
|
&mut variables,
|
|
|
|
&mut functions,
|
|
|
|
&mut type_iterators,
|
|
|
|
);
|
|
|
|
|
|
|
|
self.all_variables = variables;
|
|
|
|
self.all_functions = functions;
|
|
|
|
self.all_type_iterators = type_iterators;
|
2020-10-01 17:31:27 +02:00
|
|
|
self.indexed = true;
|
|
|
|
}
|
2020-11-21 15:18:32 +01:00
|
|
|
|
|
|
|
self
|
2020-05-07 18:19:08 +02:00
|
|
|
}
|
2020-05-13 13:21:42 +02:00
|
|
|
|
2020-11-16 07:07:48 +01:00
|
|
|
/// Does a type iterator exist in the entire module tree?
|
|
|
|
pub fn contains_qualified_iter(&self, id: TypeId) -> bool {
|
|
|
|
self.all_type_iterators.contains_key(&id)
|
|
|
|
}
|
|
|
|
|
2020-05-13 13:21:42 +02:00
|
|
|
/// Does a type iterator exist in the module?
|
2020-05-13 14:22:05 +02:00
|
|
|
pub fn contains_iter(&self, id: TypeId) -> bool {
|
2020-05-13 13:21:42 +02:00
|
|
|
self.type_iterators.contains_key(&id)
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a type iterator into the [`Module`].
|
2020-07-12 05:46:53 +02:00
|
|
|
pub fn set_iter(&mut self, typ: TypeId, func: IteratorFn) -> &mut Self {
|
2020-05-20 13:27:23 +02:00
|
|
|
self.type_iterators.insert(typ, func);
|
2020-06-27 17:56:24 +02:00
|
|
|
self.indexed = false;
|
2020-07-12 05:46:53 +02:00
|
|
|
self
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set a type iterator into the [`Module`].
|
2020-10-15 16:11:18 +02:00
|
|
|
pub fn set_iterable<T>(&mut self) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Variant + Clone + IntoIterator,
|
|
|
|
<T as IntoIterator>::Item: Variant + Clone,
|
|
|
|
{
|
2020-10-14 17:22:10 +02:00
|
|
|
self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
|
|
|
|
Box::new(obj.cast::<T>().into_iter().map(Dynamic::from))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Set an iterator type into the [`Module`] as a type iterator.
|
2020-10-15 16:11:18 +02:00
|
|
|
pub fn set_iterator<T>(&mut self) -> &mut Self
|
|
|
|
where
|
|
|
|
T: Variant + Clone + Iterator,
|
|
|
|
<T as Iterator>::Item: Variant + Clone,
|
|
|
|
{
|
2020-10-14 17:22:10 +02:00
|
|
|
self.set_iter(TypeId::of::<T>(), |obj: Dynamic| {
|
|
|
|
Box::new(obj.cast::<T>().map(Dynamic::from))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-16 07:07:48 +01:00
|
|
|
/// Get the specified type iterator.
|
|
|
|
pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<IteratorFn> {
|
|
|
|
self.all_type_iterators.get(&id).cloned()
|
|
|
|
}
|
|
|
|
|
2020-05-13 13:21:42 +02:00
|
|
|
/// Get the specified type iterator.
|
2020-06-20 04:49:15 +02:00
|
|
|
pub(crate) fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
|
2020-05-20 13:27:23 +02:00
|
|
|
self.type_iterators.get(&id).cloned()
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-25 02:36:06 +01:00
|
|
|
/// _(INTERNALS)_ A chain of [module][Module] names to namespace-qualify a variable or function call.
|
2020-07-25 09:52:27 +02:00
|
|
|
/// Exported under the `internals` feature only.
|
|
|
|
///
|
2020-12-24 16:22:50 +01:00
|
|
|
/// A [`NonZeroU64`] offset to the current [`Scope`][crate::Scope] is cached for quick search purposes.
|
2020-05-13 13:21:42 +02:00
|
|
|
///
|
2020-11-20 09:52:28 +01:00
|
|
|
/// A [`StaticVec`] is used because most namespace-qualified access contains only one level,
|
|
|
|
/// and it is wasteful to always allocate a [`Vec`] with one element.
|
2020-07-25 09:52:27 +02:00
|
|
|
///
|
2021-01-16 07:46:03 +01:00
|
|
|
/// # Volatile Data Structure
|
2020-07-25 09:52:27 +02:00
|
|
|
///
|
|
|
|
/// This type is volatile and may change.
|
2020-07-19 11:14:55 +02:00
|
|
|
#[derive(Clone, Eq, PartialEq, Default, Hash)]
|
2021-01-11 16:09:33 +01:00
|
|
|
pub struct NamespaceRef {
|
|
|
|
index: Option<NonZeroUsize>,
|
|
|
|
path: StaticVec<Ident>,
|
|
|
|
}
|
2020-05-13 13:21:42 +02:00
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
impl fmt::Debug for NamespaceRef {
|
2020-05-13 13:21:42 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-01-11 16:09:33 +01:00
|
|
|
fmt::Debug::fmt(&self.path, f)?;
|
2020-05-13 13:21:42 +02:00
|
|
|
|
2021-01-11 16:09:33 +01:00
|
|
|
if let Some(index) = self.index {
|
2020-05-13 13:21:42 +02:00
|
|
|
write!(f, " -> {}", index)
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
impl Deref for NamespaceRef {
|
2020-12-22 09:45:56 +01:00
|
|
|
type Target = StaticVec<Ident>;
|
2020-05-13 13:21:42 +02:00
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
2021-01-11 16:09:33 +01:00
|
|
|
&self.path
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
impl DerefMut for NamespaceRef {
|
2020-05-13 13:21:42 +02:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
2021-01-11 16:09:33 +01:00
|
|
|
&mut self.path
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
impl fmt::Display for NamespaceRef {
|
2020-05-13 13:21:42 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-01-11 16:09:33 +01:00
|
|
|
for Ident { name, .. } in self.path.iter() {
|
2020-10-31 17:04:02 +01:00
|
|
|
write!(f, "{}{}", name, Token::DoubleColon.syntax())?;
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-22 09:45:56 +01:00
|
|
|
impl From<StaticVec<Ident>> for NamespaceRef {
|
2021-01-11 16:09:33 +01:00
|
|
|
fn from(path: StaticVec<Ident>) -> Self {
|
|
|
|
Self { index: None, path }
|
2020-10-07 09:40:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
impl NamespaceRef {
|
2020-12-24 16:22:50 +01:00
|
|
|
/// Get the [`Scope`][crate::Scope] index offset.
|
2020-05-13 13:21:42 +02:00
|
|
|
pub(crate) fn index(&self) -> Option<NonZeroUsize> {
|
2021-01-11 16:09:33 +01:00
|
|
|
self.index
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
2020-12-24 16:22:50 +01:00
|
|
|
/// Set the [`Scope`][crate::Scope] index offset.
|
2020-10-18 16:10:08 +02:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-05-13 13:21:42 +02:00
|
|
|
pub(crate) fn set_index(&mut self, index: Option<NonZeroUsize>) {
|
2021-01-11 16:09:33 +01:00
|
|
|
self.index = index
|
2020-05-13 13:21:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-09-25 04:59:21 +02:00
|
|
|
pub use resolvers::ModuleResolver;
|
2020-05-06 13:45:17 +02:00
|
|
|
|
2021-01-02 16:30:10 +01:00
|
|
|
/// Module containing all built-in [module resolvers][ModuleResolver].
|
2020-07-07 17:44:23 +02:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-09-25 04:59:21 +02:00
|
|
|
pub mod resolvers;
|