Add storage API for NativeCallContext.
This commit is contained in:
parent
0c79471fd3
commit
b4529b6a64
@ -41,6 +41,11 @@ New features
|
|||||||
|
|
||||||
* `Scope` is now serializable and deserializable via `serde`.
|
* `Scope` is now serializable and deserializable via `serde`.
|
||||||
|
|
||||||
|
### Store and recreate `NativeCallContext`
|
||||||
|
|
||||||
|
* A convenient API is added to store a `NativeCallContext` into a new `NativeCallContextStore` type.
|
||||||
|
* This allows a `NativeCallContext` to be stored and recreated later on.
|
||||||
|
|
||||||
### Call native Rust functions in `NativeCallContext`
|
### Call native Rust functions in `NativeCallContext`
|
||||||
|
|
||||||
* `NativeCallContext::call_native_fn` is added to call registered native Rust functions only.
|
* `NativeCallContext::call_native_fn` is added to call registered native Rust functions only.
|
||||||
|
@ -72,22 +72,51 @@ pub struct NativeCallContext<'a> {
|
|||||||
/// Function source, if any.
|
/// Function source, if any.
|
||||||
source: Option<&'a str>,
|
source: Option<&'a str>,
|
||||||
/// The current [`GlobalRuntimeState`], if any.
|
/// The current [`GlobalRuntimeState`], if any.
|
||||||
global: Option<&'a GlobalRuntimeState<'a>>,
|
global: Option<&'a GlobalRuntimeState>,
|
||||||
/// The current stack of loaded [modules][Module].
|
/// The current stack of loaded [modules][Module].
|
||||||
lib: &'a [&'a Module],
|
lib: &'a [Shared<Module>],
|
||||||
/// [Position] of the function call.
|
/// [Position] of the function call.
|
||||||
pos: Position,
|
pos: Position,
|
||||||
/// The current nesting level of function calls.
|
/// The current nesting level of function calls.
|
||||||
level: usize,
|
level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// _(internals)_ Context of a native Rust function call.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct NativeCallContextStore {
|
||||||
|
/// Name of function called.
|
||||||
|
pub fn_name: String,
|
||||||
|
/// Function source, if any.
|
||||||
|
pub source: Option<String>,
|
||||||
|
/// The current [`GlobalRuntimeState`], if any.
|
||||||
|
pub global: GlobalRuntimeState,
|
||||||
|
/// The current stack of loaded [modules][Module].
|
||||||
|
pub lib: StaticVec<Shared<Module>>,
|
||||||
|
/// [Position] of the function call.
|
||||||
|
pub pos: Position,
|
||||||
|
/// The current nesting level of function calls.
|
||||||
|
pub level: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
impl NativeCallContextStore {
|
||||||
|
/// Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn create_context<'a>(&'a self, engine: &'a Engine) -> NativeCallContext<'a> {
|
||||||
|
NativeCallContext::from_stored_data(engine, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a>
|
impl<'a>
|
||||||
From<(
|
From<(
|
||||||
&'a Engine,
|
&'a Engine,
|
||||||
&'a str,
|
&'a str,
|
||||||
Option<&'a str>,
|
Option<&'a str>,
|
||||||
&'a GlobalRuntimeState<'a>,
|
&'a GlobalRuntimeState,
|
||||||
&'a [&Module],
|
&'a [Shared<Module>],
|
||||||
Position,
|
Position,
|
||||||
usize,
|
usize,
|
||||||
)> for NativeCallContext<'a>
|
)> for NativeCallContext<'a>
|
||||||
@ -99,7 +128,7 @@ impl<'a>
|
|||||||
&'a str,
|
&'a str,
|
||||||
Option<&'a str>,
|
Option<&'a str>,
|
||||||
&'a GlobalRuntimeState,
|
&'a GlobalRuntimeState,
|
||||||
&'a [&Module],
|
&'a [Shared<Module>],
|
||||||
Position,
|
Position,
|
||||||
usize,
|
usize,
|
||||||
),
|
),
|
||||||
@ -116,9 +145,9 @@ impl<'a>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<(&'a Engine, &'a str, &'a [&'a Module])> for NativeCallContext<'a> {
|
impl<'a> From<(&'a Engine, &'a str, &'a [Shared<Module>])> for NativeCallContext<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'a Engine, &'a str, &'a [&Module])) -> Self {
|
fn from(value: (&'a Engine, &'a str, &'a [Shared<Module>])) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
fn_name: value.1,
|
fn_name: value.1,
|
||||||
@ -140,7 +169,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
)]
|
)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self {
|
pub fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [Shared<Module>]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -164,7 +193,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
fn_name: &'a str,
|
fn_name: &'a str,
|
||||||
source: Option<&'a str>,
|
source: Option<&'a str>,
|
||||||
global: &'a GlobalRuntimeState,
|
global: &'a GlobalRuntimeState,
|
||||||
lib: &'a [&Module],
|
lib: &'a [Shared<Module>],
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -178,6 +207,39 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
level,
|
level,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// _(internals)_ Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_stored_data(engine: &'a Engine, context: &'a NativeCallContextStore) -> Self {
|
||||||
|
Self {
|
||||||
|
engine,
|
||||||
|
fn_name: &context.fn_name,
|
||||||
|
source: context.source.as_ref().map(String::as_str),
|
||||||
|
global: Some(&context.global),
|
||||||
|
lib: &context.lib,
|
||||||
|
pos: context.pos,
|
||||||
|
level: context.level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// _(internals)_ Store this [`NativeCallContext`] into a [`NativeCallContextClone`].
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn store_data(&self) -> NativeCallContextStore {
|
||||||
|
NativeCallContextStore {
|
||||||
|
fn_name: self.fn_name.to_string(),
|
||||||
|
source: self.source.map(|s| s.to_string()),
|
||||||
|
global: self.global.unwrap().clone(),
|
||||||
|
lib: self.lib.iter().cloned().collect(),
|
||||||
|
pos: self.pos,
|
||||||
|
level: self.level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The current [`Engine`].
|
/// The current [`Engine`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -246,14 +308,14 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
/// in reverse order (i.e. parent namespaces are iterated after child namespaces).
|
/// in reverse order (i.e. parent namespaces are iterated after child namespaces).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
|
||||||
self.lib.iter().copied()
|
self.lib.iter().map(|m| m.as_ref())
|
||||||
}
|
}
|
||||||
/// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
|
/// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn namespaces(&self) -> &[&Module] {
|
pub const fn namespaces(&self) -> &[Shared<Module>] {
|
||||||
self.lib
|
self.lib
|
||||||
}
|
}
|
||||||
/// Call a function inside the call context with the provided arguments.
|
/// Call a function inside the call context with the provided arguments.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use rhai::{
|
use rhai::{
|
||||||
module_resolvers::{DummyModuleResolver, StaticModuleResolver},
|
module_resolvers::{DummyModuleResolver, StaticModuleResolver},
|
||||||
Dynamic, Engine, EvalAltResult, FnNamespace, FnPtr, ImmutableString, Module, NativeCallContext,
|
Dynamic, Engine, EvalAltResult, FnNamespace, FnPtr, ImmutableString, Module, NativeCallContext,
|
||||||
ParseError, ParseErrorType, Scope, Shared, INT,
|
ParseError, ParseErrorType, Scope, INT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -546,44 +546,13 @@ fn test_module_context() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine.register_fn(
|
engine.register_fn(
|
||||||
"calc",
|
"calc",
|
||||||
|context: NativeCallContext, fp: FnPtr| -> Result<INT, Box<EvalAltResult>> {
|
|context: NativeCallContext, fp: FnPtr| -> Result<INT, Box<EvalAltResult>> {
|
||||||
// Store fields for later use
|
|
||||||
let engine = context.engine();
|
let engine = context.engine();
|
||||||
let fn_name = context.fn_name().to_string();
|
|
||||||
let source = context.source().map(|s| s.to_string());
|
|
||||||
let global = context.global_runtime_state().unwrap().clone();
|
|
||||||
let pos = context.position();
|
|
||||||
let call_level = context.call_level();
|
|
||||||
|
|
||||||
// Store the paths of the stack of call modules up to this point
|
// Store context for later use - requires the 'internals' feature
|
||||||
let modules_list: Vec<String> = context
|
let context_data = context.store_data();
|
||||||
.iter_namespaces()
|
|
||||||
.map(|m| m.id().unwrap_or("testing"))
|
|
||||||
.filter(|id| !id.is_empty())
|
|
||||||
.map(|id| id.to_string())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Recreate the 'NativeCallContext' - requires the 'internals' feature
|
// Recreate the 'NativeCallContext'
|
||||||
let mut libraries = Vec::<Shared<Module>>::new();
|
let new_context = context_data.create_context(engine);
|
||||||
|
|
||||||
for path in modules_list {
|
|
||||||
// Recreate the stack of call modules by resolving each path with
|
|
||||||
// the module resolver.
|
|
||||||
let module = engine.module_resolver().resolve(engine, None, &path, pos)?;
|
|
||||||
|
|
||||||
libraries.push(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
let lib: Vec<&Module> = libraries.iter().map(|m| m.as_ref()).collect();
|
|
||||||
|
|
||||||
let new_context = NativeCallContext::new_with_all_fields(
|
|
||||||
engine,
|
|
||||||
&fn_name,
|
|
||||||
source.as_ref().map(String::as_str),
|
|
||||||
&global,
|
|
||||||
&lib,
|
|
||||||
pos,
|
|
||||||
call_level,
|
|
||||||
);
|
|
||||||
|
|
||||||
fp.call_within_context(&new_context, (41 as INT,))
|
fp.call_within_context(&new_context, (41 as INT,))
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user