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

@@ -2,18 +2,14 @@
use crate::ast::{FnAccess, FnCallHashes};
use crate::engine::Imports;
use crate::fn_call::FnCallArgs;
use crate::plugin::PluginFunction;
use crate::token::is_valid_identifier;
use crate::{
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, Module, Position,
RhaiResult, StaticVec,
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Module, Position, RhaiResult,
};
use std::fmt;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
convert::{TryFrom, TryInto},
fmt, mem,
};
/// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")]
@@ -204,12 +200,12 @@ impl<'a> NativeCallContext<'a> {
pub fn call_fn_dynamic_raw(
&self,
fn_name: impl AsRef<str>,
is_method: bool,
is_method_call: bool,
args: &mut [&mut Dynamic],
) -> RhaiResult {
let fn_name = fn_name.as_ref();
let hash = if is_method {
let hash = if is_method_call {
FnCallHashes::from_script_and_native(
calc_fn_hash(fn_name, args.len() - 1),
calc_fn_hash(fn_name, args.len()),
@@ -226,8 +222,8 @@ impl<'a> NativeCallContext<'a> {
fn_name,
hash,
args,
is_method,
is_method,
is_method_call,
is_method_call,
Position::NONE,
None,
0,
@@ -271,175 +267,6 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
.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.
#[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult;