Add register getter/setter/indexer to modules.

This commit is contained in:
Stephen Chung 2020-05-30 10:28:17 +08:00
parent 2bcc51cc45
commit 666a618e40
2 changed files with 101 additions and 14 deletions

View File

@ -9,6 +9,12 @@ Regression fix
* Do not optimize script with `eval_expression` - it is assumed to be one-off and short. * Do not optimize script with `eval_expression` - it is assumed to be one-off and short.
Bug fixes
---------
* Indexing with an index or dot expression now works property (it compiled wrongly before).
For example, `let s = "hello"; s[s.len-1] = 'x';` now works property instead of an error.
Breaking changes Breaking changes
---------------- ----------------
@ -26,12 +32,15 @@ Breaking changes
normal function-call style (previously the first argument will be passed by _value_ if not called normal function-call style (previously the first argument will be passed by _value_ if not called
in method-call style). Of course, if the first argument is a calculated value (e.g. result of an in method-call style). Of course, if the first argument is a calculated value (e.g. result of an
expression), then mutating it has no effect, but at least it is not cloned. expression), then mutating it has no effect, but at least it is not cloned.
* Some built-in methods (e.g. `len` for string, `floor` for `FLOAT`) now have _property_ versions in
addition to methods to simplify coding.
New features New features
------------ ------------
* Set limit on maximum level of nesting expressions and statements to avoid panics during parsing. * Set limit on maximum level of nesting expressions and statements to avoid panics during parsing.
* New `EvalPackage` to disable `eval`. * New `EvalPackage` to disable `eval`.
* `Module::set_getter_fn`, `Module::set_setter_fn` and `Module:set_indexer_fn` to register getter/setter/indexer functions.
Speed enhancements Speed enhancements
------------------ ------------------

View File

@ -2,7 +2,7 @@
use crate::any::{Dynamic, Variant}; use crate::any::{Dynamic, Variant};
use crate::calc_fn_hash; use crate::calc_fn_hash;
use crate::engine::{Engine, FunctionsLib}; use crate::engine::{make_getter, make_setter, Engine, FunctionsLib, FUNC_INDEXER};
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn}; use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn};
use crate::parser::{ use crate::parser::{
FnAccess, FnAccess,
@ -378,9 +378,9 @@ impl Module {
) )
} }
/// Set a Rust function taking two parameters into the module, returning a hash key. /// Set a Rust getter function taking one mutable parameter, returning a hash key.
/// ///
/// If there is a similar existing Rust function, it is replaced. /// If there is a similar existing Rust getter function, it is replaced.
/// ///
/// # Examples /// # Examples
/// ///
@ -388,7 +388,30 @@ impl Module {
/// use rhai::Module; /// use rhai::Module;
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_2("calc", |x: i64, y: String| { /// let hash = module.set_getter_fn("value", |x: &mut i64| { Ok(*x) });
/// assert!(module.get_fn(hash).is_some());
/// ```
#[cfg(not(feature = "no_object"))]
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
self.set_fn_1_mut(make_getter(&name.into()), func)
}
/// Set a Rust function taking two parameters into the module, returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Examples
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_fn_2("calc", |x: i64, y: ImmutableString| {
/// Ok(x + y.len() as i64) /// Ok(x + y.len() as i64)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());
@ -417,13 +440,15 @@ impl Module {
/// Set a Rust function taking two parameters (the first one mutable) into the module, /// Set a Rust function taking two parameters (the first one mutable) into the module,
/// returning a hash key. /// returning a hash key.
/// ///
/// If there is a similar existing Rust function, it is replaced.
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use rhai::Module; /// use rhai::{Module, ImmutableString};
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_2_mut("calc", |x: &mut i64, y: String| { /// let hash = module.set_fn_2_mut("calc", |x: &mut i64, y: ImmutableString| {
/// *x += y.len() as i64; Ok(*x) /// *x += y.len() as i64; Ok(*x)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());
@ -449,6 +474,59 @@ impl Module {
) )
} }
/// Set a Rust setter function taking two parameters (the first one mutable) into the module,
/// returning a hash key.
///
/// If there is a similar existing setter Rust function, it is replaced.
///
/// # Examples
///
/// ```
/// 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(())
/// });
/// assert!(module.get_fn(hash).is_some());
/// ```
#[cfg(not(feature = "no_object"))]
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<()> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<()> + Send + Sync + 'static,
) -> u64 {
self.set_fn_2_mut(make_setter(&name.into()), func)
}
/// Set a Rust indexer function taking two parameters (the first one mutable) into the module,
/// returning a hash key.
///
/// If there is a similar existing setter Rust function, it is replaced.
///
/// # Examples
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let hash = module.set_indexer_fn(|x: &mut i64, y: ImmutableString| {
/// Ok(*x + y.len() as i64)
/// });
/// assert!(module.get_fn(hash).is_some());
/// ```
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))]
pub fn set_indexer_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
) -> u64 {
self.set_fn_2_mut(FUNC_INDEXER, func)
}
/// Set a Rust function taking three parameters into the module, returning a hash key. /// Set a Rust function taking three parameters into the module, returning a hash key.
/// ///
/// If there is a similar existing Rust function, it is replaced. /// If there is a similar existing Rust function, it is replaced.
@ -456,10 +534,10 @@ impl Module {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use rhai::Module; /// use rhai::{Module, ImmutableString};
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_3("calc", |x: i64, y: String, z: i64| { /// let hash = module.set_fn_3("calc", |x: i64, y: ImmutableString, z: i64| {
/// Ok(x + y.len() as i64 + z) /// Ok(x + y.len() as i64 + z)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());
@ -499,10 +577,10 @@ impl Module {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use rhai::Module; /// use rhai::{Module, ImmutableString};
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_3_mut("calc", |x: &mut i64, y: String, z: i64| { /// let hash = module.set_fn_3_mut("calc", |x: &mut i64, y: ImmutableString, z: i64| {
/// *x += y.len() as i64 + z; Ok(*x) /// *x += y.len() as i64 + z; Ok(*x)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());
@ -541,10 +619,10 @@ impl Module {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use rhai::Module; /// use rhai::{Module, ImmutableString};
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_4("calc", |x: i64, y: String, z: i64, _w: ()| { /// let hash = module.set_fn_4("calc", |x: i64, y: ImmutableString, z: i64, _w: ()| {
/// Ok(x + y.len() as i64 + z) /// Ok(x + y.len() as i64 + z)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());
@ -591,10 +669,10 @@ impl Module {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use rhai::Module; /// use rhai::{Module, ImmutableString};
/// ///
/// let mut module = Module::new(); /// let mut module = Module::new();
/// let hash = module.set_fn_4_mut("calc", |x: &mut i64, y: String, z: i64, _w: ()| { /// let hash = module.set_fn_4_mut("calc", |x: &mut i64, y: ImmutableString, z: i64, _w: ()| {
/// *x += y.len() as i64 + z; Ok(*x) /// *x += y.len() as i64 + z; Ok(*x)
/// }); /// });
/// assert!(module.get_fn(hash).is_some()); /// assert!(module.get_fn(hash).is_some());