use super::FnCallArgs;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
pub type RhaiResult = crate::RhaiResult;
pub use rhai_codegen::*;
pub use super::RhaiFunc;
pub use crate::{
Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, FuncRegistration, ImmutableString,
Module, NativeCallContext, Position,
};
pub use std::{any::TypeId, mem};
pub trait PluginFunc {
fn call(&self, context: Option<NativeCallContext>, args: &mut FnCallArgs) -> RhaiResult;
#[must_use]
fn is_method_call(&self) -> bool;
#[must_use]
fn has_context(&self) -> bool;
#[inline(always)]
#[must_use]
fn is_pure(&self) -> bool {
true
}
#[inline(always)]
#[must_use]
fn is_volatile(&self) -> bool {
true
}
}
#[derive(Clone, Copy)]
pub struct ModuleManifest {
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub functions: &'static [FnManifestEntry],
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub sub_modules: &'static [(&'static str, &'static ModuleManifest)],
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub init_eager: fn(&mut Module),
}
#[derive(Clone, Copy)]
pub struct FnManifestEntry {
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub name: &'static str,
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub namespace: FnNamespace,
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub func: &'static (dyn PluginFunc + Send + Sync),
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub param_types: fn(&mut dyn FnMut(&[TypeId])),
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub register: fn(&mut Module),
}
impl std::fmt::Debug for ModuleManifest {
#[cold]
#[inline(never)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ModuleManifest")
.field("functions", &self.functions)
.field("sub_modules", &self.sub_modules)
.finish_non_exhaustive()
}
}
impl std::fmt::Debug for FnManifestEntry {
#[cold]
#[inline(never)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FnManifestEntry")
.field("name", &self.name)
.field("namespace", &self.namespace)
.finish_non_exhaustive()
}
}
impl ModuleManifest {
#[inline(always)]
#[must_use]
pub const fn functions(&self) -> &'static [FnManifestEntry] {
self.functions
}
#[inline(always)]
#[must_use]
pub const fn sub_modules(&self) -> &'static [(&'static str, &'static ModuleManifest)] {
self.sub_modules
}
#[inline(always)]
pub fn init_eager(&self, module: &mut Module) {
(self.init_eager)(module);
}
pub fn for_each_fn(&'static self, flatten: bool, f: &mut dyn FnMut(&'static FnManifestEntry)) {
self.functions.iter().for_each(&mut *f);
if flatten {
for (.., m) in self.sub_modules {
m.for_each_fn(flatten, f);
}
}
}
#[must_use]
pub fn find_fn(
&'static self,
flatten: bool,
f: &mut dyn FnMut(&FnManifestEntry) -> bool,
) -> Option<&'static FnManifestEntry> {
let found = flatten
.then(|| {
let mut sub_modules = self.sub_modules.iter().rev();
sub_modules.find_map(|(.., m)| m.find_fn(flatten, f))
})
.flatten();
found.or_else(|| self.functions.iter().rev().find(|&e| f(e)))
}
}
impl FnManifestEntry {
#[inline(always)]
#[must_use]
pub const fn name(&self) -> &'static str {
self.name
}
#[inline(always)]
#[must_use]
pub const fn namespace(&self) -> FnNamespace {
self.namespace
}
#[inline(always)]
#[must_use]
pub const fn func(&self) -> &'static (dyn PluginFunc + Send + Sync) {
self.func
}
#[inline(always)]
pub fn with_param_types(&self, f: &mut dyn FnMut(&[TypeId])) {
(self.param_types)(f);
}
#[inline(always)]
pub fn register_into(&self, module: &mut Module) {
(self.register)(module);
}
#[must_use]
pub fn num_params(&self) -> usize {
let mut num_params = 0;
self.with_param_types(&mut |types| num_params = types.len());
num_params
}
#[must_use]
pub fn calc_hash(&self, path: &[&str]) -> u64 {
let is_method = self.func.is_method_call();
let mut hash = 0;
self.with_param_types(&mut |types| {
let hash_script = crate::calc_fn_hash(path.iter().copied(), self.name, types.len());
let types = types.iter().enumerate();
hash = crate::calc_fn_hash_full(
hash_script,
types.map(|(i, &t)| Module::map_type(!is_method || i > 0, t)),
);
});
hash
}
#[must_use]
pub fn calc_dynamic_hash(&self) -> Option<u64> {
let mut hash = None;
self.with_param_types(&mut |types| {
if types.contains(&TypeId::of::<Dynamic>()) {
hash = Some(crate::calc_fn_hash(None, self.name, types.len()));
}
});
hash
}
}