Split FnPtr into own file.

This commit is contained in:
Stephen Chung 2021-06-17 09:50:32 +08:00
parent 40e33fa6f9
commit 425e038f4b
11 changed files with 235 additions and 215 deletions

View File

@ -1232,7 +1232,7 @@ impl Engine {
} }
} }
let is_ref = target.is_ref(); let is_ref_mut = target.is_ref();
// Pop the last index value // Pop the last index value
let idx_val = idx_values let idx_val = idx_values
@ -1295,8 +1295,8 @@ impl Engine {
let pos = Position::NONE; let pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, pos, mods, state, lib, FN_IDX_SET, hash_set, args, is_ref_mut, true,
None, level, pos, None, level,
)?; )?;
} }
@ -1374,8 +1374,8 @@ impl Engine {
let args = &mut [target.as_mut()]; let args = &mut [target.as_mut()];
let (mut orig_val, _) = self let (mut orig_val, _) = self
.exec_fn_call( .exec_fn_call(
mods, state, lib, getter, hash, args, is_ref, true, *pos, None, mods, state, lib, getter, hash, args, is_ref_mut, true, *pos,
level, None, level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
// Try an indexer if property does not exist // Try an indexer if property does not exist
@ -1417,7 +1417,8 @@ impl Engine {
let hash = FnCallHashes::from_native(*hash_set); let hash = FnCallHashes::from_native(*hash_set);
let args = &mut [target.as_mut(), &mut new_val]; let args = &mut [target.as_mut(), &mut new_val];
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, setter, hash, args, is_ref, true, *pos, None, level, mods, state, lib, setter, hash, args, is_ref_mut, true, *pos, None,
level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
// Try an indexer if property does not exist // Try an indexer if property does not exist
@ -1428,7 +1429,7 @@ impl Engine {
let pos = Position::NONE; let pos = Position::NONE;
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, FN_IDX_SET, hash_set, args, is_ref, true, mods, state, lib, FN_IDX_SET, hash_set, args, is_ref_mut, true,
pos, None, level, pos, None, level,
) )
.map_err( .map_err(
@ -1447,7 +1448,8 @@ impl Engine {
let hash = FnCallHashes::from_native(*hash_get); let hash = FnCallHashes::from_native(*hash_get);
let args = &mut [target.as_mut()]; let args = &mut [target.as_mut()];
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, getter, hash, args, is_ref, true, *pos, None, level, mods, state, lib, getter, hash, args, is_ref_mut, true, *pos, None,
level,
) )
.map_or_else( .map_or_else(
|err| match *err { |err| match *err {
@ -1518,7 +1520,7 @@ impl Engine {
let args = &mut arg_values[..1]; let args = &mut arg_values[..1];
let (mut val, updated) = self let (mut val, updated) = self
.exec_fn_call( .exec_fn_call(
mods, state, lib, getter, hash_get, args, is_ref, true, mods, state, lib, getter, hash_get, args, is_ref_mut, true,
*pos, None, level, *pos, None, level,
) )
.or_else(|err| match *err { .or_else(|err| match *err {
@ -1564,7 +1566,7 @@ impl Engine {
let mut arg_values = [target.as_mut(), val]; let mut arg_values = [target.as_mut(), val];
let args = &mut arg_values; let args = &mut arg_values;
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, setter, hash_set, args, is_ref, true, mods, state, lib, setter, hash_set, args, is_ref_mut, true,
*pos, None, level, *pos, None, level,
) )
.or_else( .or_else(
@ -1578,7 +1580,7 @@ impl Engine {
); );
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, FN_IDX_SET, hash_set, args, mods, state, lib, FN_IDX_SET, hash_set, args,
is_ref, true, *pos, None, level, is_ref_mut, true, *pos, None, level,
) )
.or_else(|idx_err| match *idx_err { .or_else(|idx_err| match *idx_err {
EvalAltResult::ErrorIndexingType(_, _) => { EvalAltResult::ErrorIndexingType(_, _) => {

View File

@ -2,7 +2,8 @@
use crate::dynamic::Variant; use crate::dynamic::Variant;
use crate::engine::{EvalContext, Imports, State}; use crate::engine::{EvalContext, Imports, State};
use crate::fn_native::{FnCallArgs, SendSync}; use crate::fn_call::FnCallArgs;
use crate::fn_native::SendSync;
use crate::fn_register::RegisterNativeFunction; use crate::fn_register::RegisterNativeFunction;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::parse::ParseState; use crate::parse::ParseState;

View File

@ -1,7 +1,8 @@
//! Built-in implementations for common operators. //! Built-in implementations for common operators.
use crate::engine::OP_CONTAINS; use crate::engine::OP_CONTAINS;
use crate::fn_native::{FnCallArgs, NativeCallContext}; use crate::fn_call::FnCallArgs;
use crate::fn_native::NativeCallContext;
use crate::{Dynamic, ImmutableString, RhaiResult, INT}; use crate::{Dynamic, ImmutableString, RhaiResult, INT};
use std::any::TypeId; use std::any::TypeId;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]

View File

@ -7,7 +7,7 @@ use crate::engine::{
MAX_DYNAMIC_PARAMETERS, MAX_DYNAMIC_PARAMETERS,
}; };
use crate::fn_builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn}; use crate::fn_builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
use crate::fn_native::{FnAny, FnCallArgs}; use crate::fn_native::FnAny;
use crate::module::NamespaceRef; use crate::module::NamespaceRef;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::{ use crate::{
@ -30,6 +30,9 @@ use std::{
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::Map; use crate::Map;
/// Arguments to a function call, which is a list of [`&mut Dynamic`][Dynamic].
pub type FnCallArgs<'a> = [&'a mut Dynamic];
/// A type that temporarily stores a mutable reference to a `Dynamic`, /// A type that temporarily stores a mutable reference to a `Dynamic`,
/// replacing it with a cloned copy. /// replacing it with a cloned copy.
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -102,13 +105,13 @@ impl Drop for ArgBackup<'_> {
pub fn ensure_no_data_race( pub fn ensure_no_data_race(
fn_name: &str, fn_name: &str,
args: &FnCallArgs, args: &FnCallArgs,
is_ref: bool, is_method_call: bool,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
if let Some((n, _)) = args if let Some((n, _)) = args
.iter() .iter()
.enumerate() .enumerate()
.skip(if is_ref { 1 } else { 0 }) .skip(if is_method_call { 1 } else { 0 })
.find(|(_, a)| a.is_locked()) .find(|(_, a)| a.is_locked())
{ {
return EvalAltResult::ErrorDataRace( return EvalAltResult::ErrorDataRace(
@ -298,7 +301,7 @@ impl Engine {
name: &str, name: &str,
hash: u64, hash: u64,
args: &mut FnCallArgs, args: &mut FnCallArgs,
is_ref: bool, is_method_call: bool,
is_op_assign: bool, is_op_assign: bool,
pos: Position, pos: Position,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
@ -316,7 +319,7 @@ impl Engine {
// Calling pure function but the first argument is a reference? // Calling pure function but the first argument is a reference?
let mut backup: Option<ArgBackup> = None; let mut backup: Option<ArgBackup> = None;
if is_ref && func.is_pure() && !args.is_empty() { if is_method_call && func.is_pure() && !args.is_empty() {
backup = Some(Default::default()); backup = Some(Default::default());
backup.as_mut().map(|bk| bk.change_first_arg_to_copy(args)); backup.as_mut().map(|bk| bk.change_first_arg_to_copy(args));
} }
@ -629,8 +632,8 @@ impl Engine {
fn_name: &str, fn_name: &str,
hashes: FnCallHashes, hashes: FnCallHashes,
args: &mut FnCallArgs, args: &mut FnCallArgs,
is_ref: bool, is_ref_mut: bool,
_is_method: bool, _is_method_call: bool,
pos: Position, pos: Position,
_capture_scope: Option<Scope>, _capture_scope: Option<Scope>,
_level: usize, _level: usize,
@ -643,7 +646,7 @@ impl Engine {
// Check for data race. // Check for data race.
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
ensure_no_data_race(fn_name, args, is_ref)?; ensure_no_data_race(fn_name, args, is_ref_mut)?;
// These may be redirected from method style calls. // These may be redirected from method style calls.
match fn_name { match fn_name {
@ -731,7 +734,7 @@ impl Engine {
}); });
} }
let result = if _is_method { let result = if _is_method_call {
// Method call of script function - map first argument to `this` // Method call of script function - map first argument to `this`
let (first, rest) = args let (first, rest) = args
.split_first_mut() .split_first_mut()
@ -762,7 +765,7 @@ impl Engine {
// Normal call of script function // Normal call of script function
// The first argument is a reference? // The first argument is a reference?
let mut backup: Option<ArgBackup> = None; let mut backup: Option<ArgBackup> = None;
if is_ref && !args.is_empty() { if is_ref_mut && !args.is_empty() {
backup = Some(Default::default()); backup = Some(Default::default());
backup.as_mut().map(|bk| bk.change_first_arg_to_copy(args)); backup.as_mut().map(|bk| bk.change_first_arg_to_copy(args));
} }
@ -789,7 +792,9 @@ impl Engine {
// Native function call // Native function call
let hash = hashes.native; let hash = hashes.native;
self.call_native_fn(mods, state, lib, fn_name, hash, args, is_ref, false, pos) self.call_native_fn(
mods, state, lib, fn_name, hash, args, is_ref_mut, false, pos,
)
} }
/// Evaluate a list of statements with no `this` pointer. /// Evaluate a list of statements with no `this` pointer.
@ -881,7 +886,7 @@ impl Engine {
pos: Position, pos: Position,
level: usize, level: usize,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
let is_ref = target.is_ref(); let is_ref_mut = target.is_ref();
let (result, updated) = match fn_name { let (result, updated) = match fn_name {
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => { KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
@ -941,7 +946,8 @@ impl Engine {
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, fn_name, new_hash, &mut args, is_ref, true, pos, None, level, mods, state, lib, fn_name, new_hash, &mut args, is_ref_mut, true, pos, None,
level,
) )
} }
KEYWORD_FN_PTR_CURRY => { KEYWORD_FN_PTR_CURRY => {
@ -1013,7 +1019,7 @@ impl Engine {
args.extend(call_args.iter_mut()); args.extend(call_args.iter_mut());
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, fn_name, hash, &mut args, is_ref, true, pos, None, level, mods, state, lib, fn_name, hash, &mut args, is_ref_mut, true, pos, None, level,
) )
} }
}?; }?;
@ -1236,7 +1242,7 @@ impl Engine {
// Normal function call - except for Fn, curry, call and eval (handled above) // Normal function call - except for Fn, curry, call and eval (handled above)
let mut arg_values = StaticVec::with_capacity(args_expr.len()); let mut arg_values = StaticVec::with_capacity(args_expr.len());
let mut args = StaticVec::with_capacity(args_expr.len() + curry.len()); let mut args = StaticVec::with_capacity(args_expr.len() + curry.len());
let mut is_ref = false; let mut is_ref_mut = false;
let capture = if capture_scope && !scope.is_empty() { let capture = if capture_scope && !scope.is_empty() {
Some(scope.clone_visible()) Some(scope.clone_visible())
} else { } else {
@ -1278,7 +1284,7 @@ impl Engine {
args.extend(arg_values.iter_mut()) args.extend(arg_values.iter_mut())
} else { } else {
// Turn it into a method call only if the object is not shared and not a simple value // Turn it into a method call only if the object is not shared and not a simple value
is_ref = true; is_ref_mut = true;
let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared"); let obj_ref = target.take_ref().expect("never fails because `target` is a reference if it is not a value and not shared");
args.push(obj_ref); args.push(obj_ref);
args.extend(arg_values.iter_mut()); args.extend(arg_values.iter_mut());
@ -1297,7 +1303,7 @@ impl Engine {
} }
self.exec_fn_call( self.exec_fn_call(
mods, state, lib, name, hashes, &mut args, is_ref, false, pos, capture, level, mods, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, capture, level,
) )
.map(|(v, _)| v) .map(|(v, _)| v)
} }

View File

@ -2,18 +2,14 @@
use crate::ast::{FnAccess, FnCallHashes}; use crate::ast::{FnAccess, FnCallHashes};
use crate::engine::Imports; use crate::engine::Imports;
use crate::fn_call::FnCallArgs;
use crate::plugin::PluginFunction; use crate::plugin::PluginFunction;
use crate::token::is_valid_identifier;
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, Module, Position, calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Module, Position, RhaiResult,
RhaiResult, StaticVec,
}; };
use std::fmt;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{
convert::{TryFrom, TryInto},
fmt, mem,
};
/// Trait that maps to `Send + Sync` only under the `sync` feature. /// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]
@ -204,12 +200,12 @@ impl<'a> NativeCallContext<'a> {
pub fn call_fn_dynamic_raw( pub fn call_fn_dynamic_raw(
&self, &self,
fn_name: impl AsRef<str>, fn_name: impl AsRef<str>,
is_method: bool, is_method_call: bool,
args: &mut [&mut Dynamic], args: &mut [&mut Dynamic],
) -> RhaiResult { ) -> RhaiResult {
let fn_name = fn_name.as_ref(); let fn_name = fn_name.as_ref();
let hash = if is_method { let hash = if is_method_call {
FnCallHashes::from_script_and_native( FnCallHashes::from_script_and_native(
calc_fn_hash(fn_name, args.len() - 1), calc_fn_hash(fn_name, args.len() - 1),
calc_fn_hash(fn_name, args.len()), calc_fn_hash(fn_name, args.len()),
@ -226,8 +222,8 @@ impl<'a> NativeCallContext<'a> {
fn_name, fn_name,
hash, hash,
args, args,
is_method, is_method_call,
is_method, is_method_call,
Position::NONE, Position::NONE,
None, None,
0, 0,
@ -271,175 +267,6 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
.expect("resource should have no outstanding references") .expect("resource should have no outstanding references")
} }
/// Arguments to a function call, which is a list of [`&mut Dynamic`][Dynamic].
pub type FnCallArgs<'a> = [&'a mut Dynamic];
/// A general function pointer, which may carry additional (i.e. curried) argument values
/// to be passed onto a function during a call.
#[derive(Debug, Clone, Hash)]
pub struct FnPtr(Identifier, StaticVec<Dynamic>);
impl FnPtr {
/// Create a new function pointer.
#[inline(always)]
#[must_use]
pub fn new(name: impl Into<Identifier>) -> Result<Self, Box<EvalAltResult>> {
name.into().try_into()
}
/// Create a new function pointer without checking its parameters.
#[inline(always)]
#[must_use]
pub(crate) fn new_unchecked(name: Identifier, curry: StaticVec<Dynamic>) -> Self {
Self(name.into(), curry)
}
/// Get the name of the function.
#[inline(always)]
#[must_use]
pub fn fn_name(&self) -> &str {
self.get_fn_name().as_ref()
}
/// Get the name of the function.
#[inline(always)]
#[must_use]
pub(crate) fn get_fn_name(&self) -> &Identifier {
&self.0
}
/// Get the underlying data of the function pointer.
#[inline(always)]
#[must_use]
pub(crate) fn take_data(self) -> (Identifier, StaticVec<Dynamic>) {
(self.0, self.1)
}
/// Get the curried arguments.
#[inline(always)]
#[must_use]
pub fn curry(&self) -> &[Dynamic] {
self.1.as_ref()
}
/// Add a new curried argument.
#[inline(always)]
pub fn add_curry(&mut self, value: Dynamic) -> &mut Self {
self.1.push(value);
self
}
/// Set curried arguments to the function pointer.
#[inline(always)]
pub fn set_curry(&mut self, values: impl IntoIterator<Item = Dynamic>) -> &mut Self {
self.1 = values.into_iter().collect();
self
}
/// Is the function pointer curried?
#[inline(always)]
#[must_use]
pub fn is_curried(&self) -> bool {
!self.1.is_empty()
}
/// Get the number of curried arguments.
#[inline(always)]
#[must_use]
pub fn num_curried(&self) -> usize {
self.1.len()
}
/// Does the function pointer refer to an anonymous function?
///
/// Not available under `no_function`.
#[cfg(not(feature = "no_function"))]
#[inline(always)]
#[must_use]
pub fn is_anonymous(&self) -> bool {
self.0.starts_with(crate::engine::FN_ANONYMOUS)
}
/// Call the function pointer with curried arguments (if any).
///
/// If this function is a script-defined function, it must not be marked private.
///
/// # WARNING
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
/// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function.
#[inline(always)]
#[must_use]
pub fn call_dynamic(
&self,
ctx: &NativeCallContext,
this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>,
) -> RhaiResult {
let mut arg_values = arg_values.as_mut();
let mut args_data;
if self.num_curried() > 0 {
args_data = StaticVec::with_capacity(self.num_curried() + arg_values.len());
args_data.extend(self.curry().iter().cloned());
args_data.extend(arg_values.iter_mut().map(mem::take));
arg_values = args_data.as_mut();
};
let is_method = this_ptr.is_some();
let mut args = StaticVec::with_capacity(arg_values.len() + 1);
if let Some(obj) = this_ptr {
args.push(obj);
}
args.extend(arg_values.iter_mut());
ctx.call_fn_dynamic_raw(self.fn_name(), is_method, &mut args)
}
}
impl fmt::Display for FnPtr {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Fn({})", self.0)
}
}
impl TryFrom<Identifier> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: Identifier) -> Result<Self, Self::Error> {
if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default()))
} else {
EvalAltResult::ErrorFunctionNotFound(value.to_string(), Position::NONE).into()
}
}
}
#[cfg(not(feature = "no_smartstring"))]
impl TryFrom<crate::ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: crate::ImmutableString) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
impl TryFrom<String> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: String) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
impl TryFrom<&str> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: &str) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
/// A general function trail object. /// A general function trail object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult; pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult;

178
src/fn_ptr.rs Normal file
View File

@ -0,0 +1,178 @@
//! The `FnPtr` type.
use crate::token::is_valid_identifier;
use crate::{
Dynamic, EvalAltResult, Identifier, NativeCallContext, Position, RhaiResult, StaticVec,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
convert::{TryFrom, TryInto},
fmt, mem,
};
/// A general function pointer, which may carry additional (i.e. curried) argument values
/// to be passed onto a function during a call.
#[derive(Debug, Clone, Hash)]
pub struct FnPtr(Identifier, StaticVec<Dynamic>);
impl FnPtr {
/// Create a new function pointer.
#[inline(always)]
#[must_use]
pub fn new(name: impl Into<Identifier>) -> Result<Self, Box<EvalAltResult>> {
name.into().try_into()
}
/// Create a new function pointer without checking its parameters.
#[inline(always)]
#[must_use]
pub(crate) fn new_unchecked(name: Identifier, curry: StaticVec<Dynamic>) -> Self {
Self(name.into(), curry)
}
/// Get the name of the function.
#[inline(always)]
#[must_use]
pub fn fn_name(&self) -> &str {
self.get_fn_name().as_ref()
}
/// Get the name of the function.
#[inline(always)]
#[must_use]
pub(crate) fn get_fn_name(&self) -> &Identifier {
&self.0
}
/// Get the underlying data of the function pointer.
#[inline(always)]
#[must_use]
pub(crate) fn take_data(self) -> (Identifier, StaticVec<Dynamic>) {
(self.0, self.1)
}
/// Get the curried arguments.
#[inline(always)]
#[must_use]
pub fn curry(&self) -> &[Dynamic] {
self.1.as_ref()
}
/// Add a new curried argument.
#[inline(always)]
pub fn add_curry(&mut self, value: Dynamic) -> &mut Self {
self.1.push(value);
self
}
/// Set curried arguments to the function pointer.
#[inline(always)]
pub fn set_curry(&mut self, values: impl IntoIterator<Item = Dynamic>) -> &mut Self {
self.1 = values.into_iter().collect();
self
}
/// Is the function pointer curried?
#[inline(always)]
#[must_use]
pub fn is_curried(&self) -> bool {
!self.1.is_empty()
}
/// Get the number of curried arguments.
#[inline(always)]
#[must_use]
pub fn num_curried(&self) -> usize {
self.1.len()
}
/// Does the function pointer refer to an anonymous function?
///
/// Not available under `no_function`.
#[cfg(not(feature = "no_function"))]
#[inline(always)]
#[must_use]
pub fn is_anonymous(&self) -> bool {
self.0.starts_with(crate::engine::FN_ANONYMOUS)
}
/// Call the function pointer with curried arguments (if any).
///
/// If this function is a script-defined function, it must not be marked private.
///
/// # WARNING
///
/// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments.
/// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function.
#[inline(always)]
#[must_use]
pub fn call_dynamic(
&self,
ctx: &NativeCallContext,
this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>,
) -> RhaiResult {
let mut arg_values = arg_values.as_mut();
let mut args_data;
if self.num_curried() > 0 {
args_data = StaticVec::with_capacity(self.num_curried() + arg_values.len());
args_data.extend(self.curry().iter().cloned());
args_data.extend(arg_values.iter_mut().map(mem::take));
arg_values = args_data.as_mut();
};
let is_method = this_ptr.is_some();
let mut args = StaticVec::with_capacity(arg_values.len() + 1);
if let Some(obj) = this_ptr {
args.push(obj);
}
args.extend(arg_values.iter_mut());
ctx.call_fn_dynamic_raw(self.fn_name(), is_method, &mut args)
}
}
impl fmt::Display for FnPtr {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Fn({})", self.0)
}
}
impl TryFrom<Identifier> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: Identifier) -> Result<Self, Self::Error> {
if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default()))
} else {
EvalAltResult::ErrorFunctionNotFound(value.to_string(), Position::NONE).into()
}
}
}
#[cfg(not(feature = "no_smartstring"))]
impl TryFrom<crate::ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: crate::ImmutableString) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
impl TryFrom<String> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: String) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}
impl TryFrom<&str> for FnPtr {
type Error = Box<EvalAltResult>;
#[inline(always)]
fn try_from(value: &str) -> Result<Self, Self::Error> {
let s: Identifier = value.into();
Self::try_from(s)
}
}

View File

@ -3,7 +3,8 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::dynamic::{DynamicWriteLock, Variant}; use crate::dynamic::{DynamicWriteLock, Variant};
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync}; use crate::fn_call::FnCallArgs;
use crate::fn_native::{CallableFunction, FnAny, SendSync};
use crate::r#unsafe::unsafe_try_cast; use crate::r#unsafe::unsafe_try_cast;
use crate::token::Position; use crate::token::Position;
use crate::{Dynamic, EvalAltResult, NativeCallContext}; use crate::{Dynamic, EvalAltResult, NativeCallContext};

View File

@ -83,6 +83,7 @@ mod fn_call;
mod fn_func; mod fn_func;
mod fn_hash; mod fn_hash;
mod fn_native; mod fn_native;
mod fn_ptr;
mod fn_register; mod fn_register;
mod immutable_string; mod immutable_string;
mod module; mod module;
@ -132,7 +133,8 @@ pub use dynamic::Dynamic;
pub use engine::{Engine, EvalContext, OP_CONTAINS, OP_EQUALS}; pub use engine::{Engine, EvalContext, OP_CONTAINS, OP_EQUALS};
pub use error::EvalAltResult; pub use error::EvalAltResult;
pub use error_parsing::{LexError, ParseError, ParseErrorType}; pub use error_parsing::{LexError, ParseError, ParseErrorType};
pub use fn_native::{FnPtr, NativeCallContext}; pub use fn_native::NativeCallContext;
pub use fn_ptr::FnPtr;
pub use fn_register::RegisterNativeFunction; pub use fn_register::RegisterNativeFunction;
pub use immutable_string::ImmutableString; pub use immutable_string::ImmutableString;
pub use module::{FnNamespace, Module}; pub use module::{FnNamespace, Module};

View File

@ -2,7 +2,8 @@
use crate::ast::{FnAccess, Ident}; use crate::ast::{FnAccess, Ident};
use crate::dynamic::Variant; use crate::dynamic::Variant;
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync}; use crate::fn_call::FnCallArgs;
use crate::fn_native::{shared_take_or_clone, CallableFunction, IteratorFn, SendSync};
use crate::fn_register::RegisterNativeFunction; use crate::fn_register::RegisterNativeFunction;
use crate::parse::IdentifierBuilder; use crate::parse::IdentifierBuilder;
use crate::token::Token; use crate::token::Token;

View File

@ -318,7 +318,7 @@ fn parse_var_name(input: &mut TokenStream) -> Result<(String, Position), ParseEr
} }
} }
/// Parse ( expr ) /// Parse `(` expr `)`
fn parse_paren_expr( fn parse_paren_expr(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,

View File

@ -1,6 +1,7 @@
//! Module defining macros for developing _plugins_. //! Module defining macros for developing _plugins_.
pub use crate::fn_native::{CallableFunction, FnCallArgs}; use crate::fn_call::FnCallArgs;
pub use crate::fn_native::CallableFunction;
pub use crate::{ pub use crate::{
Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module,
NativeCallContext, Position, NativeCallContext, Position,