Merge pull request #622 from schungx/master

Add fallible iterators.
This commit is contained in:
Stephen Chung 2022-08-22 16:12:35 +08:00 committed by GitHub
commit 3078a281b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 217 additions and 145 deletions

View File

@ -1,6 +1,24 @@
Rhai Release Notes Rhai Release Notes
================== ==================
Version 1.10.0
==============
Bug fixes
---------
* API for registering property getters/setters and indexers to an `Engine` now works with functions that take a first parameter of `NativeCallContext`.
* Missing API function `Module::set_getter_setter_fn` is added.
New features
------------
Fallible type iterators
-----------------------
* For very special needs, the ability to register fallible type iterators is added.
Version 1.9.0 Version 1.9.0
============= =============

View File

@ -125,10 +125,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
/// Register a custom function. /// Register a custom function.
#[inline(always)] #[inline(always)]
pub fn with_fn<N, A, F>(&mut self, name: N, method: F) -> &mut Self pub fn with_fn<N, A, F, R, S>(&mut self, name: N, method: F) -> &mut Self
where where
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, ()>, F: RegisterNativeFunction<A, R, S>,
{ {
self.engine.register_fn(name, method); self.engine.register_fn(name, method);
self self
@ -136,10 +136,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
/// Register a custom fallible function. /// Register a custom fallible function.
#[inline(always)] #[inline(always)]
pub fn with_result_fn<N, A, F, R>(&mut self, name: N, method: F) -> &mut Self pub fn with_result_fn<N, A, F, R, S>(&mut self, name: N, method: F) -> &mut Self
where where
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, RhaiResultOf<R>>, F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{ {
self.engine.register_result_fn(name, method); self.engine.register_result_fn(name, method);
self self

View File

@ -72,16 +72,13 @@ impl Engine {
Token::LeftBrace => Token::MapStart, Token::LeftBrace => Token::MapStart,
// Disallowed syntax // Disallowed syntax
t @ (Token::Unit | Token::MapStart) => Token::LexError( t @ (Token::Unit | Token::MapStart) => Token::LexError(
LexError::ImproperSymbol( LexError::ImproperSymbol(t.literal_syntax().to_string(), String::new())
t.literal_syntax().to_string(), .into(),
"".to_string(),
)
.into(),
), ),
Token::InterpolatedString(..) => Token::LexError( Token::InterpolatedString(..) => Token::LexError(
LexError::ImproperSymbol( LexError::ImproperSymbol(
"interpolated string".to_string(), "interpolated string".to_string(),
"".to_string(), String::new(),
) )
.into(), .into(),
), ),
@ -93,7 +90,7 @@ impl Engine {
Some(&|token, _, _| { Some(&|token, _, _| {
match token { match token {
Token::Reserved(s) if &*s == "null" => Token::LexError( Token::Reserved(s) if &*s == "null" => Token::LexError(
LexError::ImproperSymbol("null".to_string(), "".to_string()).into(), LexError::ImproperSymbol("null".to_string(), String::new()).into(),
), ),
// `{` => `#{` // `{` => `#{`
Token::LeftBrace => Token::MapStart, Token::LeftBrace => Token::MapStart,

View File

@ -1,5 +1,6 @@
//! Module that defines the public function/module registration API of [`Engine`]. //! Module that defines the public function/module registration API of [`Engine`].
use crate::func::register::Mut;
use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync}; use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync};
use crate::types::dynamic::Variant; use crate::types::dynamic::Variant;
use crate::{ use crate::{
@ -50,10 +51,10 @@ impl Engine {
/// # } /// # }
/// ``` /// ```
#[inline] #[inline]
pub fn register_fn<N, A, F>(&mut self, name: N, func: F) -> &mut Self pub fn register_fn<N, A, F, R, S>(&mut self, name: N, func: F) -> &mut Self
where where
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, ()>, F: RegisterNativeFunction<A, R, S>,
{ {
let param_types = F::param_types(); let param_types = F::param_types();
@ -112,10 +113,10 @@ impl Engine {
/// .expect_err("expecting division by zero error!"); /// .expect_err("expecting division by zero error!");
/// ``` /// ```
#[inline] #[inline]
pub fn register_result_fn<N, A, F, R>(&mut self, name: N, func: F) -> &mut Self pub fn register_result_fn<N, A, F, R, S>(&mut self, name: N, func: F) -> &mut Self
where where
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, RhaiResultOf<R>>, F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{ {
let param_types = F::param_types(); let param_types = F::param_types();
@ -291,7 +292,7 @@ impl Engine {
.set_custom_type_raw(fully_qualified_type_path, name); .set_custom_type_raw(fully_qualified_type_path, name);
self self
} }
/// Register an type iterator for an iterable type with the [`Engine`]. /// Register a type iterator for an iterable type with the [`Engine`].
/// This is an advanced API. /// This is an advanced API.
#[inline(always)] #[inline(always)]
pub fn register_iterator<T>(&mut self) -> &mut Self pub fn register_iterator<T>(&mut self) -> &mut Self
@ -302,6 +303,17 @@ impl Engine {
self.global_namespace_mut().set_iterable::<T>(); self.global_namespace_mut().set_iterable::<T>();
self self
} }
/// Register a fallible type iterator for an iterable type with the [`Engine`].
/// This is an advanced API.
#[inline(always)]
pub fn register_iterator_result<T, X>(&mut self) -> &mut Self
where
T: Variant + Clone + IntoIterator<Item = RhaiResultOf<X>>,
X: Variant + Clone,
{
self.global_namespace_mut().set_iterable_result::<T, X>();
self
}
/// Register a getter function for a member of a registered type with the [`Engine`]. /// Register a getter function for a member of a registered type with the [`Engine`].
/// ///
/// The function signature must start with `&mut self` and not `&self`. /// The function signature must start with `&mut self` and not `&self`.
@ -344,10 +356,10 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_get<T: Variant + Clone, V: Variant + Clone>( pub fn register_get<T: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
name: impl AsRef<str>, name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> V + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn)
} }
@ -393,10 +405,10 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_get_result<T: Variant + Clone, V: Variant + Clone>( pub fn register_get_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
name: impl AsRef<str>, name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> RhaiResultOf<V> + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>,), V, RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_result_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) self.register_result_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn)
} }
@ -443,10 +455,10 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_set<T: Variant + Clone, V: Variant + Clone>( pub fn register_set<T: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
name: impl AsRef<str>, name: impl AsRef<str>,
set_fn: impl Fn(&mut T, V) + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn)
} }
@ -494,10 +506,10 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_set_result<T: Variant + Clone, V: Variant + Clone>( pub fn register_set_result<T: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
name: impl AsRef<str>, name: impl AsRef<str>,
set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_result_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) self.register_result_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn)
} }
@ -548,11 +560,11 @@ impl Engine {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn register_get_set<T: Variant + Clone, V: Variant + Clone>( pub fn register_get_set<T: Variant + Clone, V: Variant + Clone, S1, S2>(
&mut self, &mut self,
name: impl AsRef<str>, name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> V + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S1> + SendSync + 'static,
set_fn: impl Fn(&mut T, V) + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S2> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_get(&name, get_fn).register_set(&name, set_fn) self.register_get(&name, get_fn).register_set(&name, set_fn)
} }
@ -607,9 +619,9 @@ impl Engine {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline] #[inline]
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>( pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() { if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -686,9 +698,10 @@ impl Engine {
T: Variant + Clone, T: Variant + Clone,
X: Variant + Clone, X: Variant + Clone,
V: Variant + Clone, V: Variant + Clone,
S,
>( >(
&mut self, &mut self,
get_fn: impl Fn(&mut T, X) -> RhaiResultOf<V> + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() { if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -761,9 +774,9 @@ impl Engine {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline] #[inline]
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>( pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone, S>(
&mut self, &mut self,
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() { if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -841,9 +854,10 @@ impl Engine {
T: Variant + Clone, T: Variant + Clone,
X: Variant + Clone, X: Variant + Clone,
V: Variant + Clone, V: Variant + Clone,
S,
>( >(
&mut self, &mut self,
set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), RhaiResultOf<S>> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() { if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -917,10 +931,16 @@ impl Engine {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)] #[inline(always)]
pub fn register_indexer_get_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>( pub fn register_indexer_get_set<
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S1,
S2,
>(
&mut self, &mut self,
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S1> + SendSync + 'static,
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S2> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
self.register_indexer_get(get_fn) self.register_indexer_get(get_fn)
.register_indexer_set(set_fn) .register_indexer_set(set_fn)

View File

@ -90,12 +90,12 @@ fn print_error(input: &str, mut err: EvalAltResult) {
let line_no = if lines.len() > 1 { let line_no = if lines.len() > 1 {
if pos.is_none() { if pos.is_none() {
"".to_string() String::new()
} else { } else {
format!("{}: ", pos.line().unwrap()) format!("{}: ", pos.line().unwrap())
} }
} else { } else {
"".to_string() String::new()
}; };
// Print error position // Print error position

View File

@ -15,12 +15,12 @@ fn print_error(input: &str, mut err: EvalAltResult) {
let line_no = if lines.len() > 1 { let line_no = if lines.len() > 1 {
if pos.is_none() { if pos.is_none() {
"".to_string() String::new()
} else { } else {
format!("{}: ", pos.line().unwrap()) format!("{}: ", pos.line().unwrap())
} }
} else { } else {
"".to_string() String::new()
}; };
// Print error position // Print error position

View File

@ -641,38 +641,21 @@ impl Engine {
break; break;
} }
let index_value = (x as INT).into(); let index_value = Dynamic::from(x as INT);
#[cfg(not(feature = "no_closure"))] *scope.get_mut_by_index(counter_index).write_lock().unwrap() =
{ index_value;
let index_var = scope.get_mut_by_index(counter_index);
if index_var.is_shared() {
*index_var.write_lock().expect("`Dynamic`") = index_value;
} else {
*index_var = index_value;
}
}
#[cfg(feature = "no_closure")]
{
*scope.get_mut_by_index(counter_index) = index_value;
}
} }
let value = iter_value.flatten(); let value = match iter_value {
Ok(v) => v.flatten(),
#[cfg(not(feature = "no_closure"))] Err(err) => {
{ loop_result = Err(err.fill_position(expr.position()));
let loop_var = scope.get_mut_by_index(index); break;
if loop_var.is_shared() {
*loop_var.write_lock().expect("`Dynamic`") = value;
} else {
*loop_var = value;
} }
} };
#[cfg(feature = "no_closure")]
{ *scope.get_mut_by_index(index).write_lock().unwrap() = value;
*scope.get_mut_by_index(index) = value;
}
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if let Err(err) = self if let Err(err) = self

View File

@ -426,10 +426,11 @@ pub type FnBuiltin = fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult;
/// Function that gets an iterator from a type. /// Function that gets an iterator from a type.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>; pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>;
/// Function that gets an iterator from a type. /// Function that gets an iterator from a type.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send + Sync; pub type IteratorFn =
dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + Send + Sync;
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
pub type FnPlugin = dyn PluginFunction; pub type FnPlugin = dyn PluginFunction;

View File

@ -60,7 +60,7 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
} }
/// Trait to register custom Rust functions. /// Trait to register custom Rust functions.
pub trait RegisterNativeFunction<Args, Result> { pub trait RegisterNativeFunction<ARGS, RET, RESULT> {
/// Convert this function into a [`CallableFunction`]. /// Convert this function into a [`CallableFunction`].
#[must_use] #[must_use]
fn into_callable_function(self) -> CallableFunction; fn into_callable_function(self) -> CallableFunction;
@ -128,7 +128,7 @@ macro_rules! def_register {
FN: Fn($($param),*) -> RET + SendSync + 'static, FN: Fn($($param),*) -> RET + SendSync + 'static,
$($par: Variant + Clone,)* $($par: Variant + Clone,)*
RET: Variant + Clone RET: Variant + Clone
> RegisterNativeFunction<($($mark,)*), ()> for FN { > RegisterNativeFunction<($($mark,)*), RET, ()> for FN {
#[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() }
@ -154,7 +154,7 @@ macro_rules! def_register {
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RET + SendSync + 'static, FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RET + SendSync + 'static,
$($par: Variant + Clone,)* $($par: Variant + Clone,)*
RET: Variant + Clone RET: Variant + Clone
> RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), ()> for FN { > RegisterNativeFunction<($($mark,)*), RET, NativeCallContext<'static>> for FN {
#[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RET>() }
@ -180,7 +180,7 @@ macro_rules! def_register {
FN: Fn($($param),*) -> RhaiResultOf<RET> + SendSync + 'static, FN: Fn($($param),*) -> RhaiResultOf<RET> + SendSync + 'static,
$($par: Variant + Clone,)* $($par: Variant + Clone,)*
RET: Variant + Clone RET: Variant + Clone
> RegisterNativeFunction<($($mark,)*), RhaiResultOf<RET>> for FN { > RegisterNativeFunction<($($mark,)*), RET, RhaiResultOf<()>> for FN {
#[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() }
@ -203,7 +203,7 @@ macro_rules! def_register {
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResultOf<RET> + SendSync + 'static, FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResultOf<RET> + SendSync + 'static,
$($par: Variant + Clone,)* $($par: Variant + Clone,)*
RET: Variant + Clone RET: Variant + Clone
> RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), RhaiResultOf<RET>> for FN { > RegisterNativeFunction<($($mark,)*), RET, RhaiResultOf<NativeCallContext<'static>>> for FN {
#[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() }
#[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::<RhaiResultOf<RET>>() }

View File

@ -1,6 +1,7 @@
//! Module defining external-loaded modules for Rhai. //! Module defining external-loaded modules for Rhai.
use crate::ast::FnAccess; use crate::ast::FnAccess;
use crate::func::register::Mut;
use crate::func::{ use crate::func::{
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
SendSync, SendSync,
@ -1290,11 +1291,11 @@ impl Module {
/// assert!(module.contains_fn(hash)); /// assert!(module.contains_fn(hash));
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn set_native_fn<ARGS, N, T, F>(&mut self, name: N, func: F) -> u64 pub fn set_native_fn<ARGS, N, T, F, S>(&mut self, name: N, func: F) -> u64
where where
N: AsRef<str> + Into<Identifier>, N: AsRef<str> + Into<Identifier>,
T: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>, F: RegisterNativeFunction<ARGS, T, RhaiResultOf<S>>,
{ {
self.set_fn( self.set_fn(
name, name,
@ -1326,14 +1327,11 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_getter_fn<ARGS, A, T, F>(&mut self, name: impl AsRef<str>, func: F) -> u64 pub fn set_getter_fn<A, T, F, S>(&mut self, name: impl AsRef<str>, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
T: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>> F: RegisterNativeFunction<(Mut<A>,), T, RhaiResultOf<S>> + SendSync + 'static,
+ Fn(&mut A) -> RhaiResultOf<T>
+ SendSync
+ 'static,
{ {
self.set_fn( self.set_fn(
crate::engine::make_getter(name.as_ref()).as_str(), crate::engine::make_getter(name.as_ref()).as_str(),
@ -1370,14 +1368,11 @@ impl Module {
/// ``` /// ```
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
pub fn set_setter_fn<ARGS, A, B, F>(&mut self, name: impl AsRef<str>, func: F) -> u64 pub fn set_setter_fn<A, T, F, S>(&mut self, name: impl AsRef<str>, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
B: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>> F: RegisterNativeFunction<(Mut<A>, T), (), RhaiResultOf<S>> + SendSync + 'static,
+ Fn(&mut A, B) -> RhaiResultOf<()>
+ SendSync
+ 'static,
{ {
self.set_fn( self.set_fn(
crate::engine::make_setter(name.as_ref()).as_str(), crate::engine::make_setter(name.as_ref()).as_str(),
@ -1389,6 +1384,48 @@ impl Module {
) )
} }
/// Set a pair of Rust getter and setter functions into the [`Module`], returning both non-zero hash keys.
/// This is a short-hand for [`set_getter_fn`][Module::set_getter_fn] and [`set_setter_fn`][Module::set_setter_fn].
///
/// These function are automatically exposed to the global namespace.
///
/// If there are similar existing Rust functions, they are replaced.
///
/// # Function Metadata
///
/// No metadata for the function is registered.
/// Use [`update_fn_metadata`][Module::update_fn_metadata] to add metadata.
///
/// # Example
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let (hash_get, hash_set) = module.set_getter_setter_fn("value",
/// |x: &mut i64| { Ok(x.to_string().into()) },
/// |x: &mut i64, y: ImmutableString| {
/// *x = y.len() as i64;
/// Ok(())
/// }
/// );
/// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set));
/// ```
#[cfg(not(feature = "no_object"))]
#[inline(always)]
pub fn set_getter_setter_fn<A: Variant + Clone, T: Variant + Clone, S1, S2>(
&mut self,
name: impl AsRef<str>,
getter: impl RegisterNativeFunction<(Mut<A>,), T, RhaiResultOf<S1>> + SendSync + 'static,
setter: impl RegisterNativeFunction<(Mut<A>, T), (), RhaiResultOf<S2>> + SendSync + 'static,
) -> (u64, u64) {
(
self.set_getter_fn(name.as_ref(), getter),
self.set_setter_fn(name.as_ref(), setter),
)
}
/// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`], /// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`],
/// returning a non-zero hash key. /// returning a non-zero hash key.
/// This function is automatically exposed to the global namespace. /// This function is automatically exposed to the global namespace.
@ -1418,15 +1455,12 @@ impl Module {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline] #[inline]
pub fn set_indexer_get_fn<ARGS, A, B, T, F>(&mut self, func: F) -> u64 pub fn set_indexer_get_fn<A, B, T, F, S>(&mut self, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
B: Variant + Clone, B: Variant + Clone,
T: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>> F: RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S>> + SendSync + 'static,
+ Fn(&mut A, B) -> RhaiResultOf<T>
+ SendSync
+ 'static,
{ {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<A>() == TypeId::of::<crate::Array>() { if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
@ -1482,15 +1516,12 @@ impl Module {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline] #[inline]
pub fn set_indexer_set_fn<ARGS, A, B, C, F>(&mut self, func: F) -> u64 pub fn set_indexer_set_fn<A, B, T, F, S>(&mut self, func: F) -> u64
where where
A: Variant + Clone, A: Variant + Clone,
B: Variant + Clone, B: Variant + Clone,
C: Variant + Clone, T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>> F: RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S>> + SendSync + 'static,
+ Fn(&mut A, B, C) -> RhaiResultOf<()>
+ SendSync
+ 'static,
{ {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if TypeId::of::<A>() == TypeId::of::<crate::Array>() { if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
@ -1517,10 +1548,12 @@ impl Module {
) )
} }
/// Set a pair of Rust index getter and setter functions, returning both non-zero hash keys. /// Set a pair of Rust index getter and setter functions into the [`Module`], returning both non-zero hash keys.
/// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and /// 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]. /// [`set_indexer_set_fn`][Module::set_indexer_set_fn].
/// ///
/// These functions are automatically exposed to the global namespace.
///
/// If there are similar existing Rust functions, they are replaced. /// If there are similar existing Rust functions, they are replaced.
/// ///
/// # Panics /// # Panics
@ -1552,10 +1585,10 @@ impl Module {
/// ``` /// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[inline(always)] #[inline(always)]
pub fn set_indexer_get_set_fn<A, B, T>( pub fn set_indexer_get_set_fn<A, B, T, S1, S2>(
&mut self, &mut self,
get_fn: impl Fn(&mut A, B) -> RhaiResultOf<T> + SendSync + 'static, get_fn: impl RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S1>> + SendSync + 'static,
set_fn: impl Fn(&mut A, B, T) -> RhaiResultOf<()> + SendSync + 'static, set_fn: impl RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S2>> + SendSync + 'static,
) -> (u64, u64) ) -> (u64, u64)
where where
A: Variant + Clone, A: Variant + Clone,
@ -2016,7 +2049,7 @@ impl Module {
if let Some(fn_ptr) = value.downcast_ref::<crate::FnPtr>() { if let Some(fn_ptr) = value.downcast_ref::<crate::FnPtr>() {
if ast.iter_fn_def().any(|f| f.name == fn_ptr.fn_name()) { if ast.iter_fn_def().any(|f| f.name == fn_ptr.fn_name()) {
return Err(crate::ERR::ErrorMismatchDataType( return Err(crate::ERR::ErrorMismatchDataType(
"".to_string(), String::new(),
if fn_ptr.is_anonymous() { if fn_ptr.is_anonymous() {
format!("cannot export closure in variable {_name}") format!("cannot export closure in variable {_name}")
} else { } else {
@ -2217,29 +2250,23 @@ impl Module {
} }
/// Set a type iterator into the [`Module`]. /// Set a type iterator into the [`Module`].
#[cfg(not(feature = "sync"))] #[inline(always)]
#[inline]
pub fn set_iter(
&mut self,
type_id: TypeId,
func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static,
) -> &mut Self {
let func = Shared::new(func);
if self.indexed {
self.all_type_iterators.insert(type_id, func.clone());
self.contains_indexed_global_functions = true;
}
self.type_iterators.insert(type_id, func);
self
}
/// Set a type iterator into the [`Module`].
#[cfg(feature = "sync")]
#[inline]
pub fn set_iter( pub fn set_iter(
&mut self, &mut self,
type_id: TypeId, type_id: TypeId,
func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + SendSync + 'static, func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + SendSync + 'static,
) -> &mut Self {
self.set_iter_result(type_id, move |x| {
Box::new(func(x).map(Ok)) as Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>
})
}
/// Set a fallible type iterator into the [`Module`].
#[inline]
pub fn set_iter_result(
&mut self,
type_id: TypeId,
func: impl Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + SendSync + 'static,
) -> &mut Self { ) -> &mut Self {
let func = Shared::new(func); let func = Shared::new(func);
if self.indexed { if self.indexed {
@ -2251,7 +2278,7 @@ impl Module {
} }
/// Set a type iterator into the [`Module`]. /// Set a type iterator into the [`Module`].
#[inline] #[inline(always)]
pub fn set_iterable<T>(&mut self) -> &mut Self pub fn set_iterable<T>(&mut self) -> &mut Self
where where
T: Variant + Clone + IntoIterator, T: Variant + Clone + IntoIterator,
@ -2262,8 +2289,20 @@ impl Module {
}) })
} }
/// Set a fallible type iterator into the [`Module`].
#[inline(always)]
pub fn set_iterable_result<T, X>(&mut self) -> &mut Self
where
T: Variant + Clone + IntoIterator<Item = RhaiResultOf<X>>,
X: Variant + Clone,
{
self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().into_iter().map(|v| v.map(Dynamic::from)))
})
}
/// Set an iterator type into the [`Module`] as a type iterator. /// Set an iterator type into the [`Module`] as a type iterator.
#[inline] #[inline(always)]
pub fn set_iterator<T>(&mut self) -> &mut Self pub fn set_iterator<T>(&mut self) -> &mut Self
where where
T: Variant + Clone + Iterator, T: Variant + Clone + Iterator,
@ -2274,6 +2313,18 @@ impl Module {
}) })
} }
/// Set a iterator type into the [`Module`] as a fallible type iterator.
#[inline(always)]
pub fn set_iterator_result<T, X>(&mut self) -> &mut Self
where
T: Variant + Clone + Iterator<Item = RhaiResultOf<X>>,
X: Variant + Clone,
{
self.set_iter_result(TypeId::of::<T>(), |obj: Dynamic| {
Box::new(obj.cast::<T>().map(|v| v.map(Dynamic::from)))
})
}
/// Get the specified type iterator. /// Get the specified type iterator.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline] #[inline]

View File

@ -2051,12 +2051,12 @@ impl Engine {
Ok(Stmt::Assignment((op_info, (lhs, rhs).into()).into())) Ok(Stmt::Assignment((op_info, (lhs, rhs).into()).into()))
} }
// expr[???] = rhs, expr.??? = rhs // expr[???] = rhs, expr.??? = rhs
ref expr => Err(PERR::AssignmentToInvalidLHS("".to_string()) ref expr => Err(PERR::AssignmentToInvalidLHS(String::new())
.into_err(expr.position())), .into_err(expr.position())),
} }
} }
Some(err_pos) => { Some(err_pos) => {
Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(err_pos)) Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(err_pos))
} }
} }
} }
@ -2067,7 +2067,7 @@ impl Engine {
) )
.into_err(op_pos)), .into_err(op_pos)),
// expr = rhs // expr = rhs
_ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())), _ => Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(lhs.position())),
} }
} }
@ -3665,8 +3665,9 @@ impl Engine {
(Token::Pipe, ..) => break, (Token::Pipe, ..) => break,
(Token::Identifier(s), pos) => { (Token::Identifier(s), pos) => {
if params_list.iter().any(|p| p.as_str() == &*s) { if params_list.iter().any(|p| p.as_str() == &*s) {
return Err(PERR::FnDuplicatedParam("".to_string(), s.to_string()) return Err(
.into_err(pos)); PERR::FnDuplicatedParam(String::new(), s.to_string()).into_err(pos)
);
} }
let s = state.get_interned_string(s); let s = state.get_interned_string(s);
state.stack.push(s.clone(), ()); state.stack.push(s.clone(), ());

View File

@ -51,8 +51,7 @@ impl fmt::Display for LexError {
Self::ImproperSymbol(s, d) if d.is_empty() => { Self::ImproperSymbol(s, d) if d.is_empty() => {
write!(f, "Invalid symbol encountered: '{}'", s) write!(f, "Invalid symbol encountered: '{}'", s)
} }
Self::ImproperSymbol(s, d) if s.is_empty() => f.write_str(d), Self::ImproperSymbol(.., d) => f.write_str(d),
Self::ImproperSymbol(s, d) => write!(f, "{}: '{}'", d, s),
} }
} }
} }

View File

@ -25,28 +25,28 @@ fn test_assignments_bad_lhs() -> Result<(), Box<EvalAltResult>> {
.compile("(x+y) = 42;") .compile("(x+y) = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
assert_eq!( assert_eq!(
*engine *engine
.compile("foo(x) = 42;") .compile("foo(x) = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
assert_eq!( assert_eq!(
*engine *engine
.compile("true = 42;") .compile("true = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToConstant("".to_string()) ParseErrorType::AssignmentToConstant(String::new())
); );
assert_eq!( assert_eq!(
*engine *engine
.compile("123 = 42;") .compile("123 = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToConstant("".to_string()) ParseErrorType::AssignmentToConstant(String::new())
); );
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -56,21 +56,21 @@ fn test_assignments_bad_lhs() -> Result<(), Box<EvalAltResult>> {
.compile("x.foo() = 42;") .compile("x.foo() = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
assert_eq!( assert_eq!(
*engine *engine
.compile("x.foo().x.y = 42;") .compile("x.foo().x.y = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
assert_eq!( assert_eq!(
*engine *engine
.compile("x.y.z.foo() = 42;") .compile("x.y.z.foo() = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
assert_eq!( assert_eq!(
@ -78,7 +78,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box<EvalAltResult>> {
.compile("x.foo()[0] = 42;") .compile("x.foo()[0] = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
assert_eq!( assert_eq!(
@ -86,7 +86,7 @@ fn test_assignments_bad_lhs() -> Result<(), Box<EvalAltResult>> {
.compile("x[y].z.foo() = 42;") .compile("x[y].z.foo() = 42;")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::AssignmentToInvalidLHS("".to_string()) ParseErrorType::AssignmentToInvalidLHS(String::new())
); );
} }

View File

@ -303,7 +303,7 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
.compile("hello hey") .compile("hello hey")
.expect_err("should error") .expect_err("should error")
.err_type(), .err_type(),
ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), "".to_string())) ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string(), String::new()))
); );
Ok(()) Ok(())

View File

@ -1,6 +1,6 @@
#![cfg(not(feature = "no_object"))] #![cfg(not(feature = "no_object"))]
use rhai::{Engine, EvalAltResult, Scope, INT}; use rhai::{Engine, EvalAltResult, NativeCallContext, Scope, INT};
#[test] #[test]
fn test_get_set() -> Result<(), Box<EvalAltResult>> { fn test_get_set() -> Result<(), Box<EvalAltResult>> {
@ -217,12 +217,14 @@ fn test_get_set_chain_without_write_back() -> Result<(), Box<EvalAltResult>> {
.register_get_set( .register_get_set(
"value", "value",
|t: &mut Inner| t.value, |t: &mut Inner| t.value,
|_: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new), |_: NativeCallContext, _: &mut Inner, new: INT| {
panic!("Inner::value setter called with {}", new)
},
) )
.register_type::<Outer>() .register_type::<Outer>()
.register_get_set( .register_get_set(
"inner", "inner",
|t: &mut Outer| t.inner.clone(), |_: NativeCallContext, t: &mut Outer| t.inner.clone(),
|_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new), |_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new),
); );