Skip to content

Commit 7a2124a

Browse files
committed
Add binding native function to FnPtr
1 parent 72a8fe0 commit 7a2124a

File tree

12 files changed

+378
-168
lines changed

12 files changed

+378
-168
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ Bug fixes
1111
* `get_fn_metadata_list` function is marked `volatile`.
1212
* `no-std` plus `sync` should now build correctly (thanks [`stargazing-dino`](https://github.com/stargazing-dino) [947](https://github.com/rhaiscript/rhai/pull/947)).
1313

14+
New Features
15+
------------
16+
17+
* It is possible to create a function pointer (`FnPtr`) which binds to a native Rust function or closure via `FnPtr::from_dn` and `FnPtr::from_dyn_fn`. When called in script, the embedded function will be called.
18+
1419
Enhancements
1520
------------
1621

src/eval/expr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::{Caches, EvalContext, GlobalRuntimeState, Target};
44
use crate::ast::Expr;
55
use crate::packages::string_basic::{print_with_func, FUNC_TO_STRING};
6-
use crate::types::dynamic::AccessMode;
6+
use crate::types::{dynamic::AccessMode, fn_ptr::FnPtrType};
77
use crate::{Dynamic, Engine, RhaiResult, RhaiResultOf, Scope, SmartString, ERR};
88
#[cfg(feature = "no_std")]
99
use std::prelude::v1::*;
@@ -77,8 +77,8 @@ impl Engine {
7777
let val: Dynamic = crate::FnPtr {
7878
name: v.1.clone(),
7979
curry: <_>::default(),
80-
environ: None,
81-
fn_def: Some(fn_def.clone()),
80+
env: None,
81+
typ: FnPtrType::Script(fn_def.clone()),
8282
}
8383
.into();
8484
return Ok(val.into());

src/func/call.rs

Lines changed: 117 additions & 66 deletions
Large diffs are not rendered by default.

src/func/function.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub enum RhaiFunc {
5656
/// Shared reference to the [`ScriptFuncDef`][crate::ast::ScriptFuncDef] function definition.
5757
fn_def: Shared<crate::ast::ScriptFuncDef>,
5858
/// Encapsulated environment, if any.
59-
environ: Option<Shared<EncapsulatedEnviron>>,
59+
env: Option<Shared<EncapsulatedEnviron>>,
6060
},
6161
}
6262

@@ -262,7 +262,7 @@ impl RhaiFunc {
262262
| Self::Plugin { .. } => None,
263263

264264
#[cfg(not(feature = "no_function"))]
265-
Self::Script { environ, .. } => environ.as_deref(),
265+
Self::Script { env, .. } => env.as_deref(),
266266
}
267267
}
268268
/// Get a reference to an iterator function.
@@ -297,7 +297,7 @@ impl From<crate::ast::ScriptFuncDef> for RhaiFunc {
297297
fn from(fn_def: crate::ast::ScriptFuncDef) -> Self {
298298
Self::Script {
299299
fn_def: fn_def.into(),
300-
environ: None,
300+
env: None,
301301
}
302302
}
303303
}
@@ -306,10 +306,7 @@ impl From<crate::ast::ScriptFuncDef> for RhaiFunc {
306306
impl From<Shared<crate::ast::ScriptFuncDef>> for RhaiFunc {
307307
#[inline(always)]
308308
fn from(fn_def: Shared<crate::ast::ScriptFuncDef>) -> Self {
309-
Self::Script {
310-
fn_def,
311-
environ: None,
312-
}
309+
Self::Script { fn_def, env: None }
313310
}
314311
}
315312

src/func/script.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl Engine {
2727
caches: &mut Caches,
2828
scope: &mut Scope,
2929
mut this_ptr: Option<&mut Dynamic>,
30-
_environ: Option<&EncapsulatedEnviron>,
30+
_env: Option<&EncapsulatedEnviron>,
3131
fn_def: &ScriptFuncDef,
3232
args: &mut FnCallArgs,
3333
rewind_scope: bool,
@@ -94,7 +94,7 @@ impl Engine {
9494
let orig_fn_resolution_caches_len = caches.fn_resolution_caches_len();
9595

9696
#[cfg(not(feature = "no_module"))]
97-
let orig_constants = _environ.map(|environ| {
97+
let orig_constants = _env.map(|environ| {
9898
let EncapsulatedEnviron {
9999
lib,
100100
imports,
@@ -144,8 +144,7 @@ impl Engine {
144144
_ => Err(ERR::ErrorInFunctionCall(
145145
fn_def.name.to_string(),
146146
#[cfg(not(feature = "no_module"))]
147-
_environ
148-
.and_then(|environ| environ.lib.id())
147+
_env.and_then(|env| env.lib.id())
149148
.unwrap_or_else(|| global.source().unwrap_or(""))
150149
.to_string(),
151150
#[cfg(feature = "no_module")]

src/module/mod.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,7 +2350,7 @@ impl Module {
23502350
let _ = result?;
23512351

23522352
// Encapsulated environment
2353-
let environ = Shared::new(crate::ast::EncapsulatedEnviron {
2353+
let env = Shared::new(crate::ast::EncapsulatedEnviron {
23542354
#[cfg(not(feature = "no_function"))]
23552355
lib: ast.shared_lib().clone(),
23562356
imports,
@@ -2373,7 +2373,7 @@ impl Module {
23732373

23742374
value.deep_scan(|v| {
23752375
if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
2376-
fn_ptr.environ = Some(environ.clone());
2376+
fn_ptr.env = Some(env.clone());
23772377
}
23782378
});
23792379

@@ -2416,15 +2416,11 @@ impl Module {
24162416
})
24172417
.for_each(|f| {
24182418
let hash = module.set_script_fn(f.clone());
2419-
if let (
2420-
RhaiFunc::Script {
2421-
environ: ref mut e, ..
2422-
},
2423-
_,
2424-
) = module.functions.as_mut().unwrap().get_mut(&hash).unwrap()
2419+
if let (RhaiFunc::Script { env: ref mut e, .. }, _) =
2420+
module.functions.as_mut().unwrap().get_mut(&hash).unwrap()
24252421
{
24262422
// Encapsulate AST environment
2427-
*e = Some(environ.clone());
2423+
*e = Some(env.clone());
24282424
}
24292425
});
24302426

src/packages/array_basic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::api::deprecated::deprecated_array_functions;
44
use crate::engine::OP_EQUALS;
55
use crate::eval::{calc_index, calc_offset_len};
66
use crate::plugin::*;
7+
use crate::types::fn_ptr::FnPtrType;
78
use crate::{
89
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
910
Position, RhaiResultOf, ERR, INT, MAX_USIZE_INT,
@@ -1271,9 +1272,8 @@ pub mod array_functions {
12711272
let comparer = FnPtr {
12721273
name: ctx.engine().get_interned_string(OP_EQUALS),
12731274
curry: <_>::default(),
1274-
environ: None,
1275-
#[cfg(not(feature = "no_function"))]
1276-
fn_def: None,
1275+
env: None,
1276+
typ: FnPtrType::Normal,
12771277
};
12781278
dedup_by_comparer(ctx, array, comparer);
12791279
}

src/parser.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use crate::tokenizer::{
1313
is_reserved_keyword_or_symbol, is_valid_function_name, is_valid_identifier, Token, TokenStream,
1414
TokenizerControl,
1515
};
16-
use crate::types::dynamic::{AccessMode, Union};
16+
use crate::types::{
17+
dynamic::{AccessMode, Union},
18+
fn_ptr::FnPtrType,
19+
};
1720
use crate::{
1821
calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ExclusiveRange, FnArgsVec,
1922
ImmutableString, InclusiveRange, LexError, ParseError, Position, Scope, Shared, SmartString,
@@ -3677,6 +3680,7 @@ impl Engine {
36773680
skip_parameters: bool,
36783681
) -> ParseResult<Expr> {
36793682
// Build new parse state
3683+
36803684
let new_state = &mut ParseState::new(
36813685
state.external_constants,
36823686
state.input,
@@ -3810,9 +3814,8 @@ impl Engine {
38103814
let fn_ptr = crate::FnPtr {
38113815
name: fn_name,
38123816
curry: ThinVec::new(),
3813-
environ: None,
3814-
#[cfg(not(feature = "no_function"))]
3815-
fn_def: Some(fn_def.clone()),
3817+
env: None,
3818+
typ: FnPtrType::Normal,
38163819
};
38173820

38183821
let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), new_settings.pos);

src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ fn check_struct_sizes() {
7171
assert_eq!(size_of::<Scope>(), 24);
7272
assert_eq!(
7373
size_of::<FnPtr>(),
74-
32 - if cfg!(feature = "no_function") {
74+
48 - if cfg!(feature = "no_function") {
7575
WORD_SIZE
7676
} else {
7777
0

src/types/dynamic.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ impl Hash for Dynamic {
406406
Union::Blob(ref a, ..) => a.hash(state),
407407
#[cfg(not(feature = "no_object"))]
408408
Union::Map(ref m, ..) => m.hash(state),
409-
Union::FnPtr(ref f, ..) if f.environ.is_some() => {
409+
Union::FnPtr(ref f, ..) if f.env.is_some() => {
410410
unimplemented!("FnPtr with embedded environment cannot be hashed")
411411
}
412412
Union::FnPtr(ref f, ..) => {
@@ -789,11 +789,7 @@ impl fmt::Debug for Dynamic {
789789
Union::FnPtr(ref fnptr, ..) => {
790790
dict.insert(value);
791791

792-
f.write_str("Fn")?;
793-
#[cfg(not(feature = "no_function"))]
794-
if fnptr.fn_def.is_some() {
795-
f.write_str("*")?;
796-
}
792+
fmt::Display::fmt(&fnptr.typ, f)?;
797793
f.write_str("(")?;
798794
fmt::Debug::fmt(fnptr.fn_name(), f)?;
799795
for curry in &fnptr.curry {
@@ -1220,9 +1216,7 @@ impl Dynamic {
12201216
Union::Blob(..) => true,
12211217
#[cfg(not(feature = "no_object"))]
12221218
Union::Map(ref m, ..) => m.values().all(Self::is_hashable),
1223-
Union::FnPtr(ref f, ..) => {
1224-
f.environ.is_none() && f.curry().iter().all(Self::is_hashable)
1225-
}
1219+
Union::FnPtr(ref f, ..) => f.env.is_none() && f.curry().iter().all(Self::is_hashable),
12261220
#[cfg(not(feature = "no_time"))]
12271221
Union::TimeStamp(..) => false,
12281222

@@ -1297,7 +1291,7 @@ impl Dynamic {
12971291
#[cfg(not(feature = "no_object"))]
12981292
Union::Map(ref m, ..) => m.values().all(|v| checked_is_hashable(v, dict)),
12991293
Union::FnPtr(ref f, ..) => {
1300-
f.environ.is_none()
1294+
f.env.is_none()
13011295
&& f.curry().iter().all(|v| checked_is_hashable(v, dict))
13021296
}
13031297
_ => value.is_hashable(),

0 commit comments

Comments
 (0)