From 666a618e403b63e7d0e4cd815f306432eca36809 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 30 May 2020 10:28:17 +0800 Subject: [PATCH] Add register getter/setter/indexer to modules. --- RELEASES.md | 9 +++++ src/module.rs | 106 +++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 14 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 79e0af4c..286aac4a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -9,6 +9,12 @@ Regression fix * 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 ---------------- @@ -26,12 +32,15 @@ Breaking changes 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 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 ------------ * Set limit on maximum level of nesting expressions and statements to avoid panics during parsing. * 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 ------------------ diff --git a/src/module.rs b/src/module.rs index 5c5d3d67..498739b7 100644 --- a/src/module.rs +++ b/src/module.rs @@ -2,7 +2,7 @@ use crate::any::{Dynamic, Variant}; 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::parser::{ 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 /// @@ -388,7 +388,30 @@ impl Module { /// use rhai::Module; /// /// 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( + &mut self, + name: impl Into, + #[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn + 'static, + #[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn + 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) /// }); /// 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, /// returning a hash key. /// + /// If there is a similar existing Rust function, it is replaced. + /// /// # Examples /// /// ``` - /// use rhai::Module; + /// use rhai::{Module, ImmutableString}; /// /// 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) /// }); /// 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( + &mut self, + name: impl Into, + #[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( + &mut self, + #[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(FUNC_INDEXER, func) + } + /// 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. @@ -456,10 +534,10 @@ impl Module { /// # Examples /// /// ``` - /// use rhai::Module; + /// use rhai::{Module, ImmutableString}; /// /// 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) /// }); /// assert!(module.get_fn(hash).is_some()); @@ -499,10 +577,10 @@ impl Module { /// # Examples /// /// ``` - /// use rhai::Module; + /// use rhai::{Module, ImmutableString}; /// /// 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) /// }); /// assert!(module.get_fn(hash).is_some()); @@ -541,10 +619,10 @@ impl Module { /// # Examples /// /// ``` - /// use rhai::Module; + /// use rhai::{Module, ImmutableString}; /// /// 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) /// }); /// assert!(module.get_fn(hash).is_some()); @@ -591,10 +669,10 @@ impl Module { /// # Examples /// /// ``` - /// use rhai::Module; + /// use rhai::{Module, ImmutableString}; /// /// 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) /// }); /// assert!(module.get_fn(hash).is_some());