From 1a48a2d8ba86719da81a0867b86a6923546e29e0 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 23 Jul 2020 15:49:09 +0800 Subject: [PATCH] Refine currying docs. --- src/fn_native.rs | 41 +++++++++++++++++++++-------------------- src/syntax.rs | 6 ++++-- tests/call_fn.rs | 23 +++++++++++------------ 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/fn_native.rs b/src/fn_native.rs index 5c3b86a4..f9276017 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,14 +1,14 @@ //! Module containing interfaces with native-Rust functions. use crate::any::Dynamic; use crate::engine::Engine; -use crate::module::{Module, FuncReturn}; +use crate::module::{FuncReturn, Module}; use crate::parser::ScriptFnDef; use crate::result::EvalAltResult; use crate::token::{is_valid_identifier, Position}; -use crate::utils::ImmutableString; +use crate::utils::{ImmutableString, StaticVec}; use crate::Scope; -use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, rc::Rc, string::String, sync::Arc}; +use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc}; /// Trait that maps to `Send + Sync` only under the `sync` feature. #[cfg(feature = "sync")] @@ -50,7 +50,8 @@ pub fn shared_take(value: Shared) -> T { pub type FnCallArgs<'a> = [&'a mut Dynamic]; -/// A general function pointer. +/// 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, Default)] pub struct FnPtr(ImmutableString, Vec); @@ -71,34 +72,34 @@ impl FnPtr { pub(crate) fn take_data(self) -> (ImmutableString, Vec) { (self.0, self.1) } - /// Get the curried data. - pub(crate) fn curry(&self) -> &[Dynamic] { + /// Get the curried arguments. + pub fn curry(&self) -> &[Dynamic] { &self.1 } - /// A shortcut of `Engine::call_fn_dynamic` function that takes into - /// consideration curry-ed and passed arguments both. + /// Call the function pointer with curried arguments (if any). + /// + /// ## 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. pub fn call_dynamic( &self, engine: &Engine, lib: impl AsRef, - mut this_ptr: Option<&mut Dynamic>, - mut arg_values: impl AsMut<[Dynamic]> + this_ptr: Option<&mut Dynamic>, + mut arg_values: impl AsMut<[Dynamic]>, ) -> FuncReturn { - let mut args: Vec = self + let args = self .1 .iter() - .chain(arg_values.as_mut().iter()) .cloned() - .collect(); + .chain(arg_values.as_mut().iter_mut().map(|v| mem::take(v))) + .collect::>(); - engine.call_fn_dynamic( - &mut Scope::new(), - lib, - &self.0.as_ref(), - this_ptr, - args - ) + engine.call_fn_dynamic(&mut Scope::new(), lib, self.0.as_str(), this_ptr, args) } } diff --git a/src/syntax.rs b/src/syntax.rs index 654daea1..fd971f1f 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -17,7 +17,7 @@ use crate::stdlib::{ sync::Arc, }; -/// A general function trail object. +/// A general expression evaluation trait object. #[cfg(not(feature = "sync"))] pub type FnCustomSyntaxEval = dyn Fn( &Engine, @@ -25,12 +25,13 @@ pub type FnCustomSyntaxEval = dyn Fn( &mut Scope, &[Expression], ) -> Result>; -/// A general function trail object. +/// A general expression evaluation trait object. #[cfg(feature = "sync")] pub type FnCustomSyntaxEval = dyn Fn(&Engine, &mut EvalContext, &mut Scope, &[Expression]) -> Result> + Send + Sync; +/// An expression sub-tree in an AST. #[derive(Debug, Clone, Hash)] pub struct Expression<'a>(&'a Expr); @@ -71,6 +72,7 @@ impl fmt::Debug for CustomSyntax { } } +/// Context of a script evaluation process. #[derive(Debug)] pub struct EvalContext<'a, 'b: 'a, 's, 'm, 't, 'd: 't> { pub(crate) mods: &'a mut Imports<'b>, diff --git a/tests/call_fn.rs b/tests/call_fn.rs index 105789b3..e96ee63d 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -3,7 +3,6 @@ use rhai::{ Dynamic, Engine, EvalAltResult, FnPtr, Func, Module, ParseError, ParseErrorType, Scope, INT, }; use std::any::TypeId; -use std::rc::Rc; #[test] fn test_fn() -> Result<(), Box> { @@ -123,9 +122,9 @@ fn test_fn_ptr_raw() -> Result<(), Box> { engine.register_raw_fn( "bar", &[ - std::any::TypeId::of::(), - std::any::TypeId::of::(), - std::any::TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), ], move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { let fp = std::mem::take(args[1]).cast::(); @@ -161,32 +160,32 @@ fn test_fn_ptr_raw() -> Result<(), Box> { } #[test] -fn test_currying_with_registered_fn() -> Result<(), Box> { +fn test_fn_ptr_curry_call() -> Result<(), Box> { let mut module = Module::new(); module.set_raw_fn( "call_with_arg", &[TypeId::of::(), TypeId::of::()], |engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| { - std::mem::take(args[0]) - .cast::() - .call_dynamic(engine, module, None, [std::mem::take(args[1])]) + let fn_ptr = std::mem::take(args[0]).cast::(); + fn_ptr.call_dynamic(engine, module, None, [std::mem::take(args[1])]) }, ); let mut engine = Engine::new(); - engine.load_package(Rc::new(module)); + engine.load_package(module.into()); + #[cfg(not(feature = "no_object"))] assert_eq!( engine.eval::( r#" let addition = |x, y| { x + y }; - let curryed = addition.curry(100); + let curried = addition.curry(2); - call_with_arg(curryed, 5) + call_with_arg(curried, 40) "# )?, - 105 + 42 ); Ok(())