rhai/src/func/native.rs

427 lines
13 KiB
Rust
Raw Normal View History

//! Module defining interfaces to native-Rust functions.
2021-11-13 15:36:23 +01:00
use super::call::FnCallArgs;
2021-12-20 15:13:00 +01:00
use crate::ast::FnCallHashes;
2022-01-07 04:43:47 +01:00
use crate::eval::{EvalState, GlobalRuntimeState};
2020-07-26 10:10:38 +02:00
use crate::plugin::PluginFunction;
2021-11-13 15:36:23 +01:00
use crate::tokenizer::{Token, TokenizeState};
2021-12-18 05:29:04 +01:00
use crate::types::dynamic::Variant;
2020-11-16 16:10:14 +01:00
use crate::{
2021-12-27 05:27:31 +01:00
calc_fn_hash, Dynamic, Engine, EvalContext, FuncArgs, Module, Position, RhaiResult,
RhaiResultOf, StaticVec, ERR,
2020-11-16 16:10:14 +01:00
};
2021-12-20 15:13:00 +01:00
use std::any::type_name;
2021-04-17 09:15:54 +02:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
2020-07-26 04:03:59 +02:00
2020-06-18 12:39:28 +02:00
/// Trait that maps to `Send + Sync` only under the `sync` feature.
2020-05-12 10:32:22 +02:00
#[cfg(feature = "sync")]
2020-05-21 11:11:01 +02:00
pub trait SendSync: Send + Sync {}
/// Trait that maps to `Send + Sync` only under the `sync` feature.
2020-05-12 10:32:22 +02:00
#[cfg(feature = "sync")]
2020-05-21 11:11:01 +02:00
impl<T: Send + Sync> SendSync for T {}
2020-05-12 10:32:22 +02:00
2020-06-18 12:39:28 +02:00
/// Trait that maps to `Send + Sync` only under the `sync` feature.
2020-05-12 10:32:22 +02:00
#[cfg(not(feature = "sync"))]
2020-05-21 11:11:01 +02:00
pub trait SendSync {}
/// Trait that maps to `Send + Sync` only under the `sync` feature.
2020-05-12 10:32:22 +02:00
#[cfg(not(feature = "sync"))]
2020-05-21 11:11:01 +02:00
impl<T> SendSync for T {}
2020-05-12 10:32:22 +02:00
/// Immutable reference-counted container.
2020-05-12 10:32:22 +02:00
#[cfg(not(feature = "sync"))]
2021-04-17 09:15:54 +02:00
pub use std::rc::Rc as Shared;
/// Immutable reference-counted container.
2020-05-12 10:32:22 +02:00
#[cfg(feature = "sync")]
2021-04-17 09:15:54 +02:00
pub use std::sync::Arc as Shared;
2020-05-12 10:32:22 +02:00
/// Synchronized shared object.
#[cfg(not(feature = "sync"))]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2021-04-17 09:15:54 +02:00
pub use std::cell::RefCell as Locked;
2021-11-08 04:35:46 +01:00
/// Lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2021-11-08 04:35:46 +01:00
pub type LockGuard<'a, T> = std::cell::RefMut<'a, T>;
/// Synchronized shared object.
#[cfg(feature = "sync")]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2021-04-17 09:15:54 +02:00
pub use std::sync::RwLock as Locked;
2021-11-08 04:35:46 +01:00
/// Lock guard for synchronized shared object.
#[cfg(feature = "sync")]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2021-11-08 04:35:46 +01:00
pub type LockGuard<'a, T> = std::sync::RwLockWriteGuard<'a, T>;
2020-11-25 02:36:06 +01:00
/// Context of a native Rust function call.
#[derive(Debug)]
2021-03-03 15:49:57 +01:00
pub struct NativeCallContext<'a> {
2022-01-02 08:14:55 +01:00
/// The current [`Engine`].
2021-03-03 15:49:57 +01:00
engine: &'a Engine,
2022-01-02 08:14:55 +01:00
/// Name of function called.
2021-03-03 15:49:57 +01:00
fn_name: &'a str,
2022-01-02 08:14:55 +01:00
/// Function source, if any.
2021-03-03 15:49:57 +01:00
source: Option<&'a str>,
2022-01-02 08:14:55 +01:00
/// The current [`GlobalRuntimeState`], if any.
global: Option<&'a GlobalRuntimeState<'a>>,
2022-01-02 08:14:55 +01:00
/// The current stack of loaded [modules][Module].
2021-03-03 15:49:57 +01:00
lib: &'a [&'a Module],
2022-01-02 08:14:55 +01:00
/// [Position] of the function call.
2021-11-05 12:35:33 +01:00
pos: Position,
}
2021-11-28 05:41:33 +01:00
impl<'a, M: AsRef<[&'a Module]> + ?Sized, S: AsRef<str> + 'a + ?Sized>
2021-11-05 12:35:33 +01:00
From<(
&'a Engine,
2021-11-28 05:41:33 +01:00
&'a S,
Option<&'a S>,
&'a GlobalRuntimeState<'a>,
2021-11-05 12:35:33 +01:00
&'a M,
Position,
)> for NativeCallContext<'a>
2020-11-07 16:33:21 +01:00
{
2020-12-29 03:41:20 +01:00
#[inline(always)]
2021-11-05 12:35:33 +01:00
fn from(
value: (
&'a Engine,
2021-11-28 05:41:33 +01:00
&'a S,
Option<&'a S>,
2021-12-27 16:03:30 +01:00
&'a GlobalRuntimeState,
2021-11-05 12:35:33 +01:00
&'a M,
Position,
),
) -> Self {
2020-11-07 16:33:21 +01:00
Self {
engine: value.0,
2021-11-28 05:41:33 +01:00
fn_name: value.1.as_ref(),
source: value.2.map(S::as_ref),
2021-12-27 16:03:30 +01:00
global: Some(value.3),
lib: value.4.as_ref(),
2021-11-05 12:35:33 +01:00
pos: value.5,
2020-11-07 16:33:21 +01:00
}
}
}
2021-11-28 05:41:33 +01:00
impl<'a, M: AsRef<[&'a Module]> + ?Sized, S: AsRef<str> + 'a + ?Sized>
From<(&'a Engine, &'a S, &'a M)> for NativeCallContext<'a>
2020-10-20 04:54:32 +02:00
{
2020-12-29 03:41:20 +01:00
#[inline(always)]
2021-11-28 05:41:33 +01:00
fn from(value: (&'a Engine, &'a S, &'a M)) -> Self {
Self {
engine: value.0,
2021-11-28 05:41:33 +01:00
fn_name: value.1.as_ref(),
2020-12-21 16:12:45 +01:00
source: None,
2021-12-27 16:03:30 +01:00
global: None,
lib: value.2.as_ref(),
pos: Position::NONE,
}
}
}
2021-03-03 15:49:57 +01:00
impl<'a> NativeCallContext<'a> {
2021-11-28 05:41:33 +01:00
/// _(internals)_ Create a new [`NativeCallContext`].
/// Exported under the `metadata` feature only.
#[deprecated(
since = "1.3.0",
note = "`NativeCallContext::new` will be moved under `internals`. Use `FnPtr::call` to call a function pointer directly."
)]
2020-11-08 11:15:23 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-28 05:41:33 +01:00
pub fn new(
engine: &'a Engine,
fn_name: &'a (impl AsRef<str> + 'a + ?Sized),
lib: &'a [&Module],
) -> Self {
2020-11-08 11:15:23 +01:00
Self {
engine,
2021-11-28 05:41:33 +01:00
fn_name: fn_name.as_ref(),
2020-12-21 16:12:45 +01:00
source: None,
2021-12-27 16:03:30 +01:00
global: None,
lib,
pos: Position::NONE,
2020-11-08 11:15:23 +01:00
}
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ Create a new [`NativeCallContext`].
/// Exported under the `internals` feature only.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2020-11-08 11:15:23 +01:00
#[cfg(feature = "internals")]
#[cfg(not(feature = "no_module"))]
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-28 05:41:33 +01:00
pub fn new_with_all_fields(
2021-03-03 15:49:57 +01:00
engine: &'a Engine,
2021-11-28 05:41:33 +01:00
fn_name: &'a (impl AsRef<str> + 'a + ?Sized),
source: Option<&'a (impl AsRef<str> + 'a + ?Sized)>,
2021-12-27 16:03:30 +01:00
global: &'a GlobalRuntimeState,
2021-03-03 15:49:57 +01:00
lib: &'a [&Module],
2021-11-05 12:35:33 +01:00
pos: Position,
2020-11-08 11:15:23 +01:00
) -> Self {
Self {
engine,
2021-11-28 05:41:33 +01:00
fn_name: fn_name.as_ref(),
2022-01-01 10:38:32 +01:00
source: source.map(<_>::as_ref),
2021-12-27 16:03:30 +01:00
global: Some(global),
lib,
2021-11-05 12:35:33 +01:00
pos,
2020-11-08 11:15:23 +01:00
}
}
2020-11-20 09:52:28 +01:00
/// The current [`Engine`].
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn engine(&self) -> &Engine {
self.engine
}
/// Name of the function called.
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn fn_name(&self) -> &str {
self.fn_name
}
2022-01-02 08:14:55 +01:00
/// [Position] of the function call.
2021-11-05 12:35:33 +01:00
#[inline(always)]
#[must_use]
pub const fn position(&self) -> Position {
self.pos
}
2020-12-21 16:12:45 +01:00
/// The current source.
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn source(&self) -> Option<&str> {
2020-12-21 16:12:45 +01:00
self.source
}
2021-12-28 04:42:52 +01:00
/// Get an iterator over the current set of modules imported via `import` statements
/// in reverse order.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2021-01-01 10:05:06 +01:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-01-01 10:05:06 +01:00
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &Module)> {
self.global.iter().flat_map(|&m| m.iter_imports())
2021-01-01 10:05:06 +01:00
}
2021-12-28 04:42:52 +01:00
/// Get an iterator over the current set of modules imported via `import` statements in reverse order.
2021-03-03 15:49:57 +01:00
#[cfg(not(feature = "no_module"))]
2021-03-07 15:10:54 +01:00
#[allow(dead_code)]
#[inline]
2021-03-31 04:16:38 +02:00
pub(crate) fn iter_imports_raw(
&self,
) -> impl Iterator<Item = (&crate::Identifier, &Shared<Module>)> {
self.global.iter().flat_map(|&m| m.iter_imports_raw())
2021-03-03 15:49:57 +01:00
}
2022-01-02 08:14:55 +01:00
/// _(internals)_ The current [`GlobalRuntimeState`], if any.
/// Exported under the `internals` feature only.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2020-11-07 16:33:21 +01:00
#[cfg(feature = "internals")]
#[cfg(not(feature = "no_module"))]
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-12-27 16:03:30 +01:00
pub const fn global_runtime_state(&self) -> Option<&GlobalRuntimeState> {
self.global
2020-11-07 16:33:21 +01:00
}
2021-12-28 04:42:52 +01:00
/// Get an iterator over the namespaces containing definitions of all script-defined functions
/// in reverse order.
#[inline]
2021-01-01 10:05:06 +01:00
pub fn iter_namespaces(&self) -> impl Iterator<Item = &Module> {
2021-12-28 04:42:52 +01:00
self.lib.iter().rev().cloned()
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ The current set of namespaces containing definitions of all script-defined functions.
/// Exported under the `internals` feature only.
2021-01-01 10:05:06 +01:00
#[cfg(feature = "internals")]
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn namespaces(&self) -> &[&Module] {
2021-01-01 10:05:06 +01:00
self.lib
}
2021-12-18 05:29:04 +01:00
/// Call a function inside the call context with the provided arguments.
#[inline]
pub fn call_fn<T: Variant + Clone>(
&self,
fn_name: impl AsRef<str>,
args: impl FuncArgs,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<T> {
2021-12-18 05:29:04 +01:00
let mut arg_values = StaticVec::new_const();
args.parse(&mut arg_values);
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
let result = self.call_fn_raw(fn_name, false, false, &mut args)?;
let typ = self.engine().map_type_name(result.type_name());
result.try_cast().ok_or_else(|| {
2021-12-27 05:27:31 +01:00
ERR::ErrorMismatchOutputType(
2021-12-18 05:29:04 +01:00
self.engine().map_type_name(type_name::<T>()).into(),
typ.into(),
Position::NONE,
)
.into()
})
}
2020-11-08 16:00:37 +01:00
/// Call a function inside the call context.
///
2021-11-29 03:17:04 +01:00
/// If `is_method_call` is [`true`], the first argument is assumed to be the `this` pointer for
/// a script-defined function (or the object of a method call).
///
2021-11-29 06:12:47 +01:00
/// # WARNING - Low Level API
///
/// This function is very low level.
///
/// # Arguments
2020-11-08 16:00:37 +01:00
///
2021-11-29 03:17:04 +01:00
/// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
/// unnecessarily cloning the arguments.
2020-11-20 09:52:28 +01:00
///
2021-11-29 03:17:04 +01:00
/// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
/// _before_ calling this function.
2020-11-08 16:00:37 +01:00
///
2021-11-29 03:17:04 +01:00
/// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
/// not consumed.
pub fn call_fn_raw(
2020-11-30 04:20:51 +01:00
&self,
2021-11-27 16:04:45 +01:00
fn_name: impl AsRef<str>,
is_ref_mut: bool,
2021-06-17 03:50:32 +02:00
is_method_call: bool,
2020-11-08 16:00:37 +01:00
args: &mut [&mut Dynamic],
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
2021-11-27 16:04:45 +01:00
let fn_name = fn_name.as_ref();
2022-01-04 08:22:48 +01:00
let len = args.len();
2021-11-27 16:04:45 +01:00
let hash = if is_method_call {
FnCallHashes::from_all(
#[cfg(not(feature = "no_function"))]
2022-01-04 08:22:48 +01:00
calc_fn_hash(fn_name, len - 1),
calc_fn_hash(fn_name, len),
)
} else {
2022-01-04 08:22:48 +01:00
calc_fn_hash(fn_name, len).into()
};
2021-03-08 08:30:32 +01:00
self.engine()
.exec_fn_call(
2022-01-24 10:04:40 +01:00
&mut self.global.cloned().unwrap_or_else(GlobalRuntimeState::new),
&mut EvalState::new(),
self.lib,
fn_name,
hash,
args,
is_ref_mut,
is_method_call,
Position::NONE,
None,
0,
)
.map(|(r, _)| r)
2020-11-08 16:00:37 +01:00
}
}
2020-11-20 09:52:28 +01:00
/// Consume a [`Shared`] resource and return a mutable reference to the wrapped value.
2020-05-26 08:14:03 +02:00
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
2020-11-09 15:44:20 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2020-05-25 11:01:39 +02:00
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
2021-03-04 07:08:11 +01:00
Shared::make_mut(value)
2020-05-25 11:01:39 +02:00
}
2020-11-20 09:52:28 +01:00
/// Consume a [`Shared`] resource if is unique (i.e. not shared), or clone it otherwise.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2020-11-09 15:44:20 +01:00
pub fn shared_take_or_clone<T: Clone>(value: Shared<T>) -> T {
shared_try_take(value).unwrap_or_else(|v| v.as_ref().clone())
}
2020-11-20 09:52:28 +01:00
/// Consume a [`Shared`] resource if is unique (i.e. not shared).
2020-11-09 15:44:20 +01:00
#[inline(always)]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2020-08-08 11:04:21 +02:00
pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
2021-03-04 07:08:11 +01:00
Shared::try_unwrap(value)
2020-08-08 10:24:10 +02:00
}
2020-11-20 09:52:28 +01:00
/// Consume a [`Shared`] resource, assuming that it is unique (i.e. not shared).
2020-05-26 08:14:03 +02:00
///
/// # Panics
///
/// Panics if the resource is shared (i.e. has other outstanding references).
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2020-08-08 11:04:21 +02:00
pub fn shared_take<T>(value: Shared<T>) -> T {
2021-11-13 05:23:35 +01:00
shared_try_take(value).ok().expect("not shared")
2020-05-25 11:01:39 +02:00
}
2021-11-08 05:07:49 +01:00
/// Lock a [`Shared`] resource.
2021-11-08 04:35:46 +01:00
#[inline(always)]
#[must_use]
2021-11-08 05:07:49 +01:00
#[allow(dead_code)]
2021-11-08 04:35:46 +01:00
pub fn shared_write_lock<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> {
#[cfg(not(feature = "sync"))]
return value.borrow_mut();
#[cfg(feature = "sync")]
return value.write().unwrap();
}
2020-06-25 12:07:57 +02:00
/// A general function trail object.
2020-05-19 16:25:57 +02:00
#[cfg(not(feature = "sync"))]
2021-03-02 08:02:28 +01:00
pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult;
2020-06-25 12:07:57 +02:00
/// A general function trail object.
2020-05-19 16:25:57 +02:00
#[cfg(feature = "sync")]
2021-03-02 08:02:28 +01:00
pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult + Send + Sync;
2020-05-19 16:25:57 +02:00
2021-12-25 16:49:14 +01:00
/// A trail object for built-in functions.
pub type FnBuiltin = fn(NativeCallContext, &mut FnCallArgs) -> RhaiResult;
2020-06-18 12:39:28 +02:00
/// A standard function that gets an iterator from a type.
2022-01-27 16:55:32 +01:00
#[cfg(not(feature = "sync"))]
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
/// A standard function that gets an iterator from a type.
#[cfg(feature = "sync")]
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send + Sync;
2020-05-19 16:25:57 +02:00
2020-07-02 06:47:24 +02:00
#[cfg(not(feature = "sync"))]
pub type FnPlugin = dyn PluginFunction;
#[cfg(feature = "sync")]
pub type FnPlugin = dyn PluginFunction + Send + Sync;
2020-07-02 06:47:24 +02:00
2020-12-12 03:10:27 +01:00
/// A standard callback function for progress reporting.
2021-04-25 09:27:58 +02:00
#[cfg(not(feature = "unchecked"))]
2020-06-02 07:33:16 +02:00
#[cfg(not(feature = "sync"))]
2022-01-27 16:55:32 +01:00
pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic>;
2020-12-12 03:10:27 +01:00
/// A standard callback function for progress reporting.
2021-04-25 09:27:58 +02:00
#[cfg(not(feature = "unchecked"))]
2020-06-02 07:33:16 +02:00
#[cfg(feature = "sync")]
2022-01-27 16:55:32 +01:00
pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic> + Send + Sync;
2020-12-12 03:10:27 +01:00
/// A standard callback function for printing.
#[cfg(not(feature = "sync"))]
2022-01-27 16:55:32 +01:00
pub type OnPrintCallback = dyn Fn(&str);
2020-12-12 03:10:27 +01:00
/// A standard callback function for printing.
#[cfg(feature = "sync")]
2022-01-27 16:55:32 +01:00
pub type OnPrintCallback = dyn Fn(&str) + Send + Sync;
2020-12-12 04:47:18 +01:00
/// A standard callback function for debugging.
#[cfg(not(feature = "sync"))]
2022-01-27 16:55:32 +01:00
pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position);
2020-12-12 04:47:18 +01:00
/// A standard callback function for debugging.
#[cfg(feature = "sync")]
2022-01-27 16:55:32 +01:00
pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync;
2020-12-12 03:10:27 +01:00
2021-09-24 12:00:48 +02:00
/// A standard callback function for mapping tokens during parsing.
#[cfg(not(feature = "sync"))]
pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token;
2021-09-24 12:00:48 +02:00
/// A standard callback function for mapping tokens during parsing.
#[cfg(feature = "sync")]
2022-01-27 16:55:32 +01:00
pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token + Send + Sync;
2021-09-24 12:00:48 +02:00
2020-12-12 03:10:27 +01:00
/// A standard callback function for variable access.
2020-10-11 15:58:11 +02:00
#[cfg(not(feature = "sync"))]
2022-01-27 16:55:32 +01:00
pub type OnVarCallback = dyn Fn(&str, usize, &EvalContext) -> RhaiResultOf<Option<Dynamic>>;
2020-12-12 03:10:27 +01:00
/// A standard callback function for variable access.
2020-10-11 15:58:11 +02:00
#[cfg(feature = "sync")]
2021-12-27 04:43:11 +01:00
pub type OnVarCallback =
2022-01-27 16:55:32 +01:00
dyn Fn(&str, usize, &EvalContext) -> RhaiResultOf<Option<Dynamic>> + Send + Sync;