Skip to content

Commit 8ed4ea3

Browse files
authored
Merge pull request #952 from schungx/master
Bind native function to FnPtr
2 parents fc83d6b + 7789ec4 commit 8ed4ea3

File tree

13 files changed

+420
-186
lines changed

13 files changed

+420
-186
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/api/register.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,14 +792,14 @@ impl Engine {
792792
#[allow(dead_code)]
793793
pub(crate) fn collect_fn_metadata_impl<T>(
794794
&self,
795-
ctx: Option<&NativeCallContext>,
795+
_ctx: Option<&NativeCallContext>,
796796
mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
797797
include_standard_packages: bool,
798798
) -> Vec<T> {
799799
let mut list = Vec::new();
800800

801801
#[cfg(not(feature = "no_function"))]
802-
if let Some(ctx) = ctx {
802+
if let Some(ctx) = _ctx {
803803
ctx.iter_namespaces()
804804
.flat_map(Module::iter_fn)
805805
.filter_map(|(func, f)| {
@@ -829,7 +829,7 @@ impl Engine {
829829
.for_each(|v| list.push(v));
830830

831831
#[cfg(not(feature = "no_module"))]
832-
if let Some(ctx) = ctx {
832+
if let Some(ctx) = _ctx {
833833
use crate::engine::NAMESPACE_SEPARATOR;
834834
use crate::SmartString;
835835

src/eval/expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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: crate::types::fn_ptr::FnPtrType::Script(fn_def.clone()),
8282
}
8383
.into();
8484
return Ok(val.into());

src/func/call.rs

Lines changed: 145 additions & 80 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: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,7 +2350,8 @@ impl Module {
23502350
let _ = result?;
23512351

23522352
// Encapsulated environment
2353-
let environ = Shared::new(crate::ast::EncapsulatedEnviron {
2353+
#[cfg(not(feature = "no_function"))]
2354+
let env = Shared::new(crate::ast::EncapsulatedEnviron {
23542355
#[cfg(not(feature = "no_function"))]
23552356
lib: ast.shared_lib().clone(),
23562357
imports,
@@ -2363,17 +2364,18 @@ impl Module {
23632364
while i > 0 {
23642365
i -= 1;
23652366

2366-
let (mut value, mut aliases) = if i >= orig_scope_len {
2367+
let (mut _value, mut aliases) = if i >= orig_scope_len {
23672368
let (_, v, a) = scope.pop_entry().unwrap();
23682369
(v, a)
23692370
} else {
23702371
let (_, v, a) = scope.get_entry_by_index(i);
23712372
(v.clone(), a.to_vec())
23722373
};
23732374

2374-
value.deep_scan(|v| {
2375+
#[cfg(not(feature = "no_function"))]
2376+
_value.deep_scan(|v| {
23752377
if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
2376-
fn_ptr.environ = Some(environ.clone());
2378+
fn_ptr.env = Some(env.clone());
23772379
}
23782380
});
23792381

@@ -2382,7 +2384,7 @@ impl Module {
23822384
1 => {
23832385
let alias = aliases.pop().unwrap();
23842386
if !module.contains_var(&alias) {
2385-
module.set_var(alias, value);
2387+
module.set_var(alias, _value);
23862388
}
23872389
}
23882390
_ => {
@@ -2396,12 +2398,12 @@ impl Module {
23962398
if first_alias.is_none() {
23972399
first_alias = Some(alias);
23982400
} else {
2399-
module.set_var(alias, value.clone());
2401+
module.set_var(alias, _value.clone());
24002402
}
24012403
}
24022404

24032405
if let Some(alias) = first_alias {
2404-
module.set_var(alias, value);
2406+
module.set_var(alias, _value);
24052407
}
24062408
}
24072409
}
@@ -2416,15 +2418,11 @@ impl Module {
24162418
})
24172419
.for_each(|f| {
24182420
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()
2421+
if let (RhaiFunc::Script { env: ref mut e, .. }, _) =
2422+
module.functions.as_mut().unwrap().get_mut(&hash).unwrap()
24252423
{
24262424
// Encapsulate AST environment
2427-
*e = Some(environ.clone());
2425+
*e = Some(env.clone());
24282426
}
24292427
});
24302428

src/packages/array_basic.rs

Lines changed: 3 additions & 2 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,9 @@ pub mod array_functions {
12711272
let comparer = FnPtr {
12721273
name: ctx.engine().get_interned_string(OP_EQUALS),
12731274
curry: <_>::default(),
1274-
environ: None,
12751275
#[cfg(not(feature = "no_function"))]
1276-
fn_def: None,
1276+
env: None,
1277+
typ: FnPtrType::Normal,
12771278
};
12781279
dedup_by_comparer(ctx, array, comparer);
12791280
}

src/parser.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3677,6 +3677,7 @@ impl Engine {
36773677
skip_parameters: bool,
36783678
) -> ParseResult<Expr> {
36793679
// Build new parse state
3680+
36803681
let new_state = &mut ParseState::new(
36813682
state.external_constants,
36823683
state.input,
@@ -3810,9 +3811,9 @@ impl Engine {
38103811
let fn_ptr = crate::FnPtr {
38113812
name: fn_name,
38123813
curry: ThinVec::new(),
3813-
environ: None,
38143814
#[cfg(not(feature = "no_function"))]
3815-
fn_def: Some(fn_def.clone()),
3815+
env: None,
3816+
typ: crate::types::fn_ptr::FnPtrType::Normal,
38163817
};
38173818

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

src/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ 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") {
75-
WORD_SIZE
74+
48 - if cfg!(feature = "no_function") {
75+
2 * WORD_SIZE
7676
} else {
7777
0
7878
}

0 commit comments

Comments
 (0)