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
==================
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
=============

View File

@ -125,10 +125,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
/// Register a custom function.
#[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
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, ()>,
F: RegisterNativeFunction<A, R, S>,
{
self.engine.register_fn(name, method);
self
@ -136,10 +136,10 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
/// Register a custom fallible function.
#[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
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, RhaiResultOf<R>>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
self.engine.register_result_fn(name, method);
self

View File

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

View File

@ -1,5 +1,6 @@
//! Module that defines the public function/module registration API of [`Engine`].
use crate::func::register::Mut;
use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync};
use crate::types::dynamic::Variant;
use crate::{
@ -50,10 +51,10 @@ impl Engine {
/// # }
/// ```
#[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
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, ()>,
F: RegisterNativeFunction<A, R, S>,
{
let param_types = F::param_types();
@ -112,10 +113,10 @@ impl Engine {
/// .expect_err("expecting division by zero error!");
/// ```
#[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
N: AsRef<str> + Into<Identifier>,
F: RegisterNativeFunction<A, RhaiResultOf<R>>,
F: RegisterNativeFunction<A, R, RhaiResultOf<S>>,
{
let param_types = F::param_types();
@ -291,7 +292,7 @@ impl Engine {
.set_custom_type_raw(fully_qualified_type_path, name);
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.
#[inline(always)]
pub fn register_iterator<T>(&mut self) -> &mut Self
@ -302,6 +303,17 @@ impl Engine {
self.global_namespace_mut().set_iterable::<T>();
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`].
///
/// The function signature must start with `&mut self` and not `&self`.
@ -344,10 +356,10 @@ impl Engine {
/// ```
#[cfg(not(feature = "no_object"))]
#[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,
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 {
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"))]
#[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,
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 {
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"))]
#[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,
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 {
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"))]
#[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,
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 {
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"))]
#[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,
name: impl AsRef<str>,
get_fn: impl Fn(&mut T) -> V + SendSync + 'static,
set_fn: impl Fn(&mut T, V) + SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>,), V, S1> + SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, V), (), S2> + SendSync + 'static,
) -> &mut Self {
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")))]
#[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,
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S> + SendSync + 'static,
) -> &mut Self {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -686,9 +698,10 @@ impl Engine {
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&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 {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -761,9 +774,9 @@ impl Engine {
/// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[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,
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S> + SendSync + 'static,
) -> &mut Self {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -841,9 +854,10 @@ impl Engine {
T: Variant + Clone,
X: Variant + Clone,
V: Variant + Clone,
S,
>(
&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 {
#[cfg(not(feature = "no_index"))]
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
@ -917,10 +931,16 @@ impl Engine {
/// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[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,
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<T>, X), V, S1> + SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<T>, X, V), (), S2> + SendSync + 'static,
) -> &mut Self {
self.register_indexer_get(get_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 {
if pos.is_none() {
"".to_string()
String::new()
} else {
format!("{}: ", pos.line().unwrap())
}
} else {
"".to_string()
String::new()
};
// Print error position

View File

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

View File

@ -641,38 +641,21 @@ impl Engine {
break;
}
let index_value = (x as INT).into();
let index_value = Dynamic::from(x as INT);
#[cfg(not(feature = "no_closure"))]
{
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;
}
*scope.get_mut_by_index(counter_index).write_lock().unwrap() =
index_value;
}
let value = iter_value.flatten();
let value = match iter_value {
Ok(v) => v.flatten(),
Err(err) => {
loop_result = Err(err.fill_position(expr.position()));
break;
}
};
#[cfg(not(feature = "no_closure"))]
{
let loop_var = scope.get_mut_by_index(index);
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) = value;
}
*scope.get_mut_by_index(index).write_lock().unwrap() = value;
#[cfg(not(feature = "unchecked"))]
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.
#[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.
#[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"))]
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.
pub trait RegisterNativeFunction<Args, Result> {
pub trait RegisterNativeFunction<ARGS, RET, RESULT> {
/// Convert this function into a [`CallableFunction`].
#[must_use]
fn into_callable_function(self) -> CallableFunction;
@ -128,7 +128,7 @@ macro_rules! def_register {
FN: Fn($($param),*) -> RET + SendSync + 'static,
$($par: 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() }
#[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>() }
@ -154,7 +154,7 @@ macro_rules! def_register {
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RET + SendSync + 'static,
$($par: 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() }
#[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>() }
@ -180,7 +180,7 @@ macro_rules! def_register {
FN: Fn($($param),*) -> RhaiResultOf<RET> + SendSync + 'static,
$($par: 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() }
#[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>>() }
@ -203,7 +203,7 @@ macro_rules! def_register {
FN: for<'a> Fn(NativeCallContext<'a>, $($param),*) -> RhaiResultOf<RET> + SendSync + 'static,
$($par: 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() }
#[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>>() }

View File

@ -1,6 +1,7 @@
//! Module defining external-loaded modules for Rhai.
use crate::ast::FnAccess;
use crate::func::register::Mut;
use crate::func::{
shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction,
SendSync,
@ -1290,11 +1291,11 @@ impl Module {
/// assert!(module.contains_fn(hash));
/// ```
#[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
N: AsRef<str> + Into<Identifier>,
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>,
F: RegisterNativeFunction<ARGS, T, RhaiResultOf<S>>,
{
self.set_fn(
name,
@ -1326,14 +1327,11 @@ impl Module {
/// ```
#[cfg(not(feature = "no_object"))]
#[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
A: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>
+ Fn(&mut A) -> RhaiResultOf<T>
+ SendSync
+ 'static,
F: RegisterNativeFunction<(Mut<A>,), T, RhaiResultOf<S>> + SendSync + 'static,
{
self.set_fn(
crate::engine::make_getter(name.as_ref()).as_str(),
@ -1370,14 +1368,11 @@ impl Module {
/// ```
#[cfg(not(feature = "no_object"))]
#[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
A: Variant + Clone,
B: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>
+ Fn(&mut A, B) -> RhaiResultOf<()>
+ SendSync
+ 'static,
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>, T), (), RhaiResultOf<S>> + SendSync + 'static,
{
self.set_fn(
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`],
/// returning a non-zero hash key.
/// 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")))]
#[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
A: Variant + Clone,
B: Variant + Clone,
T: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<T>>
+ Fn(&mut A, B) -> RhaiResultOf<T>
+ SendSync
+ 'static,
F: RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S>> + SendSync + 'static,
{
#[cfg(not(feature = "no_index"))]
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
@ -1482,15 +1516,12 @@ impl Module {
/// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[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
A: Variant + Clone,
B: Variant + Clone,
C: Variant + Clone,
F: RegisterNativeFunction<ARGS, RhaiResultOf<()>>
+ Fn(&mut A, B, C) -> RhaiResultOf<()>
+ SendSync
+ 'static,
T: Variant + Clone,
F: RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S>> + SendSync + 'static,
{
#[cfg(not(feature = "no_index"))]
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
/// [`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.
///
/// # Panics
@ -1552,10 +1585,10 @@ impl Module {
/// ```
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[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,
get_fn: impl Fn(&mut A, B) -> RhaiResultOf<T> + SendSync + 'static,
set_fn: impl Fn(&mut A, B, T) -> RhaiResultOf<()> + SendSync + 'static,
get_fn: impl RegisterNativeFunction<(Mut<A>, B), T, RhaiResultOf<S1>> + SendSync + 'static,
set_fn: impl RegisterNativeFunction<(Mut<A>, B, T), (), RhaiResultOf<S2>> + SendSync + 'static,
) -> (u64, u64)
where
A: Variant + Clone,
@ -2016,7 +2049,7 @@ impl Module {
if let Some(fn_ptr) = value.downcast_ref::<crate::FnPtr>() {
if ast.iter_fn_def().any(|f| f.name == fn_ptr.fn_name()) {
return Err(crate::ERR::ErrorMismatchDataType(
"".to_string(),
String::new(),
if fn_ptr.is_anonymous() {
format!("cannot export closure in variable {_name}")
} else {
@ -2217,29 +2250,23 @@ impl Module {
}
/// Set a type iterator into the [`Module`].
#[cfg(not(feature = "sync"))]
#[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]
#[inline(always)]
pub fn set_iter(
&mut self,
type_id: TypeId,
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 {
let func = Shared::new(func);
if self.indexed {
@ -2251,7 +2278,7 @@ impl Module {
}
/// Set a type iterator into the [`Module`].
#[inline]
#[inline(always)]
pub fn set_iterable<T>(&mut self) -> &mut Self
where
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.
#[inline]
#[inline(always)]
pub fn set_iterator<T>(&mut self) -> &mut Self
where
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.
#[cfg(not(feature = "no_module"))]
#[inline]

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#![cfg(not(feature = "no_object"))]
use rhai::{Engine, EvalAltResult, Scope, INT};
use rhai::{Engine, EvalAltResult, NativeCallContext, Scope, INT};
#[test]
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(
"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_get_set(
"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),
);