2020-03-08 12:54:02 +01:00
//! Module which defines the function registration mechanism.
2020-07-23 12:40:42 +02:00
2020-03-18 05:04:26 +01:00
#![ allow(non_snake_case) ]
2020-11-16 16:10:14 +01:00
use crate ::dynamic ::{ DynamicWriteLock , Variant } ;
use crate ::fn_native ::{ CallableFunction , FnAny , FnCallArgs , SendSync } ;
2020-07-13 07:40:51 +02:00
use crate ::r#unsafe ::unsafe_cast_box ;
2020-08-04 12:39:24 +02:00
use crate ::stdlib ::{ any ::TypeId , boxed ::Box , mem , string ::String } ;
2020-11-17 05:23:53 +01:00
use crate ::{
2021-03-02 08:02:28 +01:00
Dynamic , Engine , FnAccess , FnNamespace , ImmutableString , NativeCallContext , RhaiResult ,
2020-11-17 05:23:53 +01:00
} ;
2016-02-29 22:43:45 +01:00
2020-11-25 02:36:06 +01:00
/// Trait to register custom functions with the [`Engine`].
2017-12-20 12:16:14 +01:00
pub trait RegisterFn < FN , ARGS , RET > {
2020-11-25 02:36:06 +01:00
/// Register a custom function with the [`Engine`].
2020-03-19 06:52:10 +01:00
///
/// # Example
///
/// ```
2020-04-21 17:25:12 +02:00
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// use rhai::{Engine, RegisterFn};
///
/// // Normal function
/// fn add(x: i64, y: i64) -> i64 {
/// x + y
/// }
///
/// let mut engine = Engine::new();
///
/// // You must use the trait rhai::RegisterFn to get this method.
/// engine.register_fn("add", add);
///
/// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
///
/// // You can also register a closure.
/// engine.register_fn("sub", |x: i64, y: i64| x - y );
///
/// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
/// # Ok(())
/// # }
/// ```
2020-07-12 05:46:53 +02:00
fn register_fn ( & mut self , name : & str , f : FN ) -> & mut Self ;
2016-02-29 22:43:45 +01:00
}
2020-03-04 15:00:01 +01:00
2021-03-03 15:49:29 +01:00
/// Trait to register fallible custom functions returning [`Result`]`<`[`Dynamic`]`, `[`Box`]`<`[`EvalAltResult`][crate::EvalAltResult]`>>` with the [`Engine`].
2020-05-22 07:09:17 +02:00
pub trait RegisterResultFn < FN , ARGS > {
2020-11-25 02:36:06 +01:00
/// Register a custom fallible function with the [`Engine`].
2020-03-19 06:52:10 +01:00
///
/// # Example
///
/// ```
2020-05-22 07:09:17 +02:00
/// use rhai::{Engine, Dynamic, RegisterResultFn, EvalAltResult};
2020-03-19 06:52:10 +01:00
///
/// // Normal function
2021-03-02 16:08:54 +01:00
/// fn div(x: i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
2020-03-19 06:52:10 +01:00
/// if y == 0 {
2020-04-21 17:25:12 +02:00
/// // '.into()' automatically converts to 'Box<EvalAltResult::ErrorRuntime>'
2020-03-25 04:24:06 +01:00
/// Err("division by zero!".into())
2020-03-19 06:52:10 +01:00
/// } else {
2020-05-22 07:09:17 +02:00
/// Ok((x / y).into())
2020-03-19 06:52:10 +01:00
/// }
/// }
///
/// let mut engine = Engine::new();
///
/// // You must use the trait rhai::RegisterResultFn to get this method.
/// engine.register_result_fn("div", div);
///
/// engine.eval::<i64>("div(42, 0)")
/// .expect_err("expecting division by zero error!");
/// ```
2020-07-12 05:46:53 +02:00
fn register_result_fn ( & mut self , name : & str , f : FN ) -> & mut Self ;
2020-03-08 15:47:13 +01:00
}
2020-03-25 04:24:06 +01:00
// These types are used to build a unique _marker_ tuple type for each combination
// of function parameter types in order to make each trait implementation unique.
2020-03-25 10:21:58 +01:00
// That is because stable Rust currently does not allow distinguishing implementations
2020-11-25 02:36:06 +01:00
// based purely on parameter types of traits (`Fn`, `FnOnce` and `FnMut`).
2020-03-25 04:24:06 +01:00
//
// For example:
//
// `RegisterFn<FN, (Mut<A>, B, Ref<C>), R>`
//
// will have the function prototype constraint to:
//
// `FN: (&mut A, B, &C) -> R`
//
// These types are not actually used anywhere.
2020-03-25 10:21:58 +01:00
pub struct Mut < T > ( T ) ;
//pub struct Ref<T>(T);
2016-04-17 04:32:18 +02:00
2020-07-27 06:30:09 +02:00
/// Dereference into DynamicWriteLock
2020-05-11 07:36:50 +02:00
#[ inline(always) ]
2020-07-27 06:30:09 +02:00
pub fn by_ref < T : Variant + Clone > ( data : & mut Dynamic ) -> DynamicWriteLock < T > {
// Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data.
data . write_lock ::< T > ( ) . unwrap ( )
2020-03-24 09:57:35 +01:00
}
2020-05-03 10:54:24 +02:00
/// Dereference into value.
2020-05-11 07:36:50 +02:00
#[ inline(always) ]
2020-05-12 10:32:22 +02:00
pub fn by_value < T : Variant + Clone > ( data : & mut Dynamic ) -> T {
2020-06-07 11:54:33 +02:00
if TypeId ::of ::< T > ( ) = = TypeId ::of ::< & str > ( ) {
2021-03-06 03:44:55 +01:00
// If T is `&str`, data must be `ImmutableString`, so map directly to it
// Beware - `Dynamic::as_str_ref` panics if `data` is shared,
// but this should not happen for argument which is passed by value
assert! ( ! data . is_shared ( ) ) ;
let ref_str = data
. as_str_ref ( )
. expect ( " argument passed by value should not be shared " ) ;
let ref_t = unsafe { mem ::transmute ::< _ , & T > ( & ref_str ) } ;
ref_t . clone ( )
2020-07-13 07:40:51 +02:00
} else if TypeId ::of ::< T > ( ) = = TypeId ::of ::< String > ( ) {
2021-03-06 03:44:55 +01:00
// If T is `String`, data must be `ImmutableString`, so map directly to it
* unsafe_cast_box ( Box ::new ( mem ::take ( data ) . take_string ( ) . unwrap ( ) ) ) . unwrap ( )
2020-06-07 11:54:33 +02:00
} else {
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
mem ::take ( data ) . cast ::< T > ( )
}
2020-04-20 18:11:25 +02:00
}
2020-04-19 16:58:44 +02:00
/// This macro creates a closure wrapping a registered function.
macro_rules ! make_func {
2020-07-27 06:30:09 +02:00
( $fn :ident : $map :expr ; $( $par :ident = > $let :stmt = > $convert :expr = > $arg :expr ) , * ) = > {
2020-05-11 07:36:50 +02:00
// ^ function pointer
2020-05-13 13:21:42 +02:00
// ^ result mapping function
// ^ function parameter generic type name (A, B, C etc.)
2020-07-27 06:30:09 +02:00
// ^ argument let statement(e.g. let mut A ...)
// ^ dereferencing function
// ^ argument reference expression(like A, *B, &mut C etc)
2020-04-19 16:58:44 +02:00
2020-10-18 11:02:17 +02:00
Box ::new ( move | _ : NativeCallContext , args : & mut FnCallArgs | {
2020-05-11 04:29:33 +02:00
// The arguments are assumed to be of the correct number and types!
2020-04-19 16:58:44 +02:00
2020-07-26 07:51:09 +02:00
let mut _drain = args . iter_mut ( ) ;
2020-07-27 06:30:09 +02:00
$( $let ) *
$( $par = ( $convert ) ( _drain . next ( ) . unwrap ( ) ) ; ) *
2020-04-19 16:58:44 +02:00
2021-03-03 04:40:27 +01:00
// Call the function with each argument value
2020-07-27 06:30:09 +02:00
let r = $fn ( $( $arg ) , * ) ;
2020-05-03 10:54:24 +02:00
// Map the result
2020-05-13 15:58:38 +02:00
$map ( r )
2020-05-19 16:25:57 +02:00
} ) as Box < FnAny >
2020-04-19 16:58:44 +02:00
} ;
}
/// To Dynamic mapping function.
2020-05-11 07:36:50 +02:00
#[ inline(always) ]
2021-03-02 08:02:28 +01:00
pub fn map_dynamic ( data : impl Variant + Clone ) -> RhaiResult {
2020-04-19 16:58:44 +02:00
Ok ( data . into_dynamic ( ) )
}
/// To Dynamic mapping function.
2020-05-11 07:36:50 +02:00
#[ inline(always) ]
2021-03-02 08:02:28 +01:00
pub fn map_result ( data : RhaiResult ) -> RhaiResult {
2020-05-22 07:09:17 +02:00
data
2020-04-19 16:58:44 +02:00
}
2020-07-13 07:40:51 +02:00
/// Remap `&str` | `String` to `ImmutableString`.
2020-06-07 11:54:33 +02:00
#[ inline(always) ]
2021-03-06 07:41:35 +01:00
fn map_type_id < R : 'static , T : 'static > ( ) -> TypeId {
let ref_id = TypeId ::of ::< R > ( ) ;
2020-06-07 11:54:33 +02:00
2021-03-06 07:41:35 +01:00
if ref_id = = TypeId ::of ::< & str > ( ) {
2020-06-07 11:54:33 +02:00
TypeId ::of ::< ImmutableString > ( )
2021-03-06 07:41:35 +01:00
} else if ref_id = = TypeId ::of ::< String > ( ) {
2020-07-13 07:40:51 +02:00
TypeId ::of ::< ImmutableString > ( )
2020-06-07 11:54:33 +02:00
} else {
2021-03-06 07:41:35 +01:00
TypeId ::of ::< T > ( )
2020-06-07 11:54:33 +02:00
}
}
2017-12-20 12:16:14 +01:00
macro_rules ! def_register {
( ) = > {
2020-05-19 16:25:57 +02:00
def_register! ( imp from_pure :) ;
2017-12-20 12:16:14 +01:00
} ;
2020-07-27 06:30:09 +02:00
( imp $abi :ident : $( $par :ident = > $arg :expr = > $mark :ty = > $param :ty = > $let :stmt = > $clone :expr ) , * ) = > {
2020-05-11 12:55:58 +02:00
// ^ function ABI type
2020-05-22 07:09:17 +02:00
// ^ function parameter generic type name (A, B, C etc.)
2020-10-02 08:55:02 +02:00
// ^ call argument(like A, *B, &mut C etc)
2020-07-27 06:30:09 +02:00
// ^ function parameter marker type (T, Ref<T> or Mut<T>)
// ^ function parameter actual type (T, &T or &mut T)
// ^ argument let statement
2020-02-25 08:02:27 +01:00
impl <
2020-04-12 17:00:06 +02:00
$( $par : Variant + Clone , ) *
2020-06-08 08:10:16 +02:00
FN : Fn ( $( $param ) , * ) -> RET + SendSync + 'static ,
2020-04-12 17:00:06 +02:00
RET : Variant + Clone
2020-04-16 17:31:48 +02:00
> RegisterFn < FN , ( $( $mark , ) * ) , RET > for Engine
2017-12-20 12:16:14 +01:00
{
2021-03-04 11:13:47 +01:00
#[ inline(always) ]
2020-07-12 05:46:53 +02:00
fn register_fn ( & mut self , name : & str , f : FN ) -> & mut Self {
2020-11-22 10:21:34 +01:00
self . global_namespace . set_fn ( name , FnNamespace ::Global , FnAccess ::Public , None ,
2021-03-06 07:41:35 +01:00
& [ $( map_type_id ::< $param , $par > ( ) ) , * ] ,
2020-07-27 06:30:09 +02:00
CallableFunction ::$abi ( make_func! ( f : map_dynamic ; $( $par = > $let = > $clone = > $arg ) , * ) )
2020-05-13 13:21:42 +02:00
) ;
2020-07-12 05:46:53 +02:00
self
2020-02-23 15:48:46 +01:00
}
}
2020-02-25 08:02:27 +01:00
impl <
2020-04-12 17:00:06 +02:00
$( $par : Variant + Clone , ) *
2021-03-02 08:02:28 +01:00
FN : Fn ( $( $param ) , * ) -> RhaiResult + SendSync + 'static ,
2020-05-22 07:09:17 +02:00
> RegisterResultFn < FN , ( $( $mark , ) * ) > for Engine
2020-03-08 15:47:13 +01:00
{
2021-03-04 11:13:47 +01:00
#[ inline(always) ]
2020-07-12 05:46:53 +02:00
fn register_result_fn ( & mut self , name : & str , f : FN ) -> & mut Self {
2020-11-22 10:21:34 +01:00
self . global_namespace . set_fn ( name , FnNamespace ::Global , FnAccess ::Public , None ,
2021-03-06 07:41:35 +01:00
& [ $( map_type_id ::< $param , $par > ( ) ) , * ] ,
2020-07-27 06:30:09 +02:00
CallableFunction ::$abi ( make_func! ( f : map_result ; $( $par = > $let = > $clone = > $arg ) , * ) )
2020-05-13 13:21:42 +02:00
) ;
2020-07-12 05:46:53 +02:00
self
2020-03-08 15:47:13 +01:00
}
}
2017-12-20 12:16:14 +01:00
//def_register!(imp_pop $($par => $mark => $param),*);
} ;
( $p0 :ident $(, $p :ident ) * ) = > {
2020-07-27 06:30:09 +02:00
def_register! ( imp from_pure : $p0 = > $p0 = > $p0 = > $p0 = > let $p0 = > by_value $(, $p = > $p = > $p = > $p = > let $p = > by_value ) * ) ;
def_register! ( imp from_method : $p0 = > & mut $p0 = > Mut < $p0 > = > & mut $p0 = > let mut $p0 = > by_ref $(, $p = > $p = > $p = > $p = > let $p = > by_value ) * ) ;
2020-05-19 13:03:06 +02:00
// ^ CallableFunction
2020-07-27 06:30:09 +02:00
// handle the first parameter ^ first parameter passed through
// ^ others passed by value (by_value)
2017-12-20 12:16:14 +01:00
2020-04-09 12:45:49 +02:00
// Currently does not support first argument which is a reference, as there will be
// conflicting implementations since &T: Any and T: Any cannot be distinguished
2020-05-03 10:54:24 +02:00
//def_register!(imp $p0 => Ref<$p0> => &$p0 => by_ref $(, $p => $p => $p => by_value)*);
2020-03-25 10:21:58 +01:00
2017-12-20 12:16:14 +01:00
def_register! ( $( $p ) , * ) ;
} ;
2016-03-02 16:49:24 +01:00
}
2020-03-25 10:21:58 +01:00
def_register! ( A , B , C , D , E , F , G , H , J , K , L , M , N , P , Q , R , S , T , U , V ) ;