use crate::any::Dynamic;
use crate::engine::Engine;
use crate::module::Module;
use crate::parser::{FnAccess, ScriptFnDef};
use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position};
use crate::utils::ImmutableString;
#[cfg(not(feature = "no_function"))]
use crate::{calc_fn_hash, module::FuncReturn, utils::StaticVec};
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, string::String, vec::Vec};
#[cfg(not(feature = "no_function"))]
use crate::stdlib::{iter::empty, mem};
#[cfg(not(feature = "sync"))]
use crate::stdlib::rc::Rc;
#[cfg(feature = "sync")]
use crate::stdlib::sync::Arc;
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
use crate::stdlib::cell::RefCell;
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
use crate::stdlib::sync::RwLock;
#[cfg(feature = "sync")]
pub trait SendSync: Send + Sync {}
#[cfg(feature = "sync")]
impl<T: Send + Sync> SendSync for T {}
#[cfg(not(feature = "sync"))]
pub trait SendSync {}
#[cfg(not(feature = "sync"))]
impl<T> SendSync for T {}
#[cfg(not(feature = "sync"))]
pub type Shared<T> = Rc<T>;
#[cfg(feature = "sync")]
pub type Shared<T> = Arc<T>;
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "sync"))]
pub type SharedMut<T> = Shared<RefCell<T>>;
#[cfg(not(feature = "no_closure"))]
#[cfg(feature = "sync")]
pub type SharedMut<T> = Shared<RwLock<T>>;
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
#[cfg(not(feature = "sync"))]
return Rc::make_mut(value);
#[cfg(feature = "sync")]
return Arc::make_mut(value);
}
pub fn shared_take<T: Clone>(value: Shared<T>) -> T {
#[cfg(not(feature = "sync"))]
return Rc::try_unwrap(value).map_err(|_| ()).unwrap();
#[cfg(feature = "sync")]
return Arc::try_unwrap(value).map_err(|_| ()).unwrap();
}
pub type FnCallArgs<'a> = [&'a mut Dynamic];
#[derive(Debug, Clone, Default)]
pub struct FnPtr(ImmutableString, Vec<Dynamic>);
impl FnPtr {
pub(crate) fn new_unchecked<S: Into<ImmutableString>>(name: S, curry: Vec<Dynamic>) -> Self {
Self(name.into(), curry)
}
pub fn fn_name(&self) -> &str {
self.get_fn_name().as_ref()
}
pub(crate) fn get_fn_name(&self) -> &ImmutableString {
&self.0
}
pub(crate) fn take_data(self) -> (ImmutableString, Vec<Dynamic>) {
(self.0, self.1)
}
pub fn curry(&self) -> &[Dynamic] {
&self.1
}
#[cfg(not(feature = "no_function"))]
pub fn call_dynamic(
&self,
engine: &Engine,
lib: impl AsRef<Module>,
this_ptr: Option<&mut Dynamic>,
mut arg_values: impl AsMut<[Dynamic]>,
) -> FuncReturn<Dynamic> {
let mut args_data = self
.1
.iter()
.cloned()
.chain(arg_values.as_mut().iter_mut().map(|v| mem::take(v)))
.collect::<StaticVec<_>>();
let has_this = this_ptr.is_some();
let args_len = args_data.len();
let mut args = args_data.iter_mut().collect::<StaticVec<_>>();
if let Some(obj) = this_ptr {
args.insert(0, obj);
}
let fn_name = self.0.as_str();
let hash_script = calc_fn_hash(empty(), fn_name, args_len, empty());
engine
.exec_fn_call(
&mut Default::default(),
lib.as_ref(),
fn_name,
hash_script,
args.as_mut(),
has_this,
has_this,
true,
None,
None,
0,
)
.map(|(v, _)| v)
}
}
impl fmt::Display for FnPtr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Fn({})", self.0)
}
}
impl TryFrom<ImmutableString> for FnPtr {
type Error = Box<EvalAltResult>;
fn try_from(value: ImmutableString) -> Result<Self, Self::Error> {
if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default()))
} else {
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
value.into(),
Position::none(),
)))
}
}
}
impl TryFrom<String> for FnPtr {
type Error = Box<EvalAltResult>;
fn try_from(value: String) -> Result<Self, Self::Error> {
let s: ImmutableString = value.into();
Self::try_from(s)
}
}
impl TryFrom<&str> for FnPtr {
type Error = Box<EvalAltResult>;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let s: ImmutableString = value.into();
Self::try_from(s)
}
}
#[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
#[cfg(feature = "sync")]
pub type FnAny =
dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
#[cfg(not(feature = "sync"))]
pub type Callback<T, R> = Box<dyn Fn(&T) -> R + 'static>;
#[cfg(feature = "sync")]
pub type Callback<T, R> = Box<dyn Fn(&T) -> R + Send + Sync + 'static>;
#[derive(Clone)]
pub enum CallableFunction {
Pure(Shared<FnAny>),
Method(Shared<FnAny>),
Iterator(IteratorFn),
#[cfg(not(feature = "no_function"))]
Script(Shared<ScriptFnDef>),
}
impl fmt::Debug for CallableFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Pure(_) => write!(f, "NativePureFunction"),
Self::Method(_) => write!(f, "NativeMethod"),
Self::Iterator(_) => write!(f, "NativeIterator"),
#[cfg(not(feature = "no_function"))]
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
}
}
}
impl fmt::Display for CallableFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Pure(_) => write!(f, "NativePureFunction"),
Self::Method(_) => write!(f, "NativeMethod"),
Self::Iterator(_) => write!(f, "NativeIterator"),
#[cfg(not(feature = "no_function"))]
CallableFunction::Script(s) => fmt::Display::fmt(s, f),
}
}
}
impl CallableFunction {
pub fn is_pure(&self) -> bool {
match self {
Self::Pure(_) => true,
Self::Method(_) | Self::Iterator(_) => false,
#[cfg(not(feature = "no_function"))]
Self::Script(_) => false,
}
}
pub fn is_method(&self) -> bool {
match self {
Self::Method(_) => true,
Self::Pure(_) | Self::Iterator(_) => false,
#[cfg(not(feature = "no_function"))]
Self::Script(_) => false,
}
}
pub fn is_iter(&self) -> bool {
match self {
Self::Iterator(_) => true,
Self::Pure(_) | Self::Method(_) => false,
#[cfg(not(feature = "no_function"))]
Self::Script(_) => false,
}
}
pub fn is_script(&self) -> bool {
match self {
#[cfg(not(feature = "no_function"))]
Self::Script(_) => true,
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => false,
}
}
pub fn is_native(&self) -> bool {
match self {
Self::Pure(_) | Self::Method(_) => true,
Self::Iterator(_) => true,
#[cfg(not(feature = "no_function"))]
Self::Script(_) => false,
}
}
pub fn access(&self) -> FnAccess {
match self {
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => FnAccess::Public,
#[cfg(not(feature = "no_function"))]
Self::Script(f) => f.access,
}
}
pub fn get_native_fn(&self) -> &FnAny {
match self {
Self::Pure(f) | Self::Method(f) => f.as_ref(),
Self::Iterator(_) => unreachable!(),
#[cfg(not(feature = "no_function"))]
Self::Script(_) => unreachable!(),
}
}
#[cfg(not(feature = "no_function"))]
pub fn get_shared_fn_def(&self) -> Shared<ScriptFnDef> {
match self {
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
Self::Script(f) => f.clone(),
}
}
pub fn get_fn_def(&self) -> &ScriptFnDef {
match self {
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
#[cfg(not(feature = "no_function"))]
Self::Script(f) => f,
}
}
pub fn get_iter_fn(&self) -> IteratorFn {
match self {
Self::Iterator(f) => *f,
Self::Pure(_) | Self::Method(_) => unreachable!(),
#[cfg(not(feature = "no_function"))]
Self::Script(_) => unreachable!(),
}
}
pub fn from_pure(func: Box<FnAny>) -> Self {
Self::Pure(func.into())
}
pub fn from_method(func: Box<FnAny>) -> Self {
Self::Method(func.into())
}
}
impl From<IteratorFn> for CallableFunction {
fn from(func: IteratorFn) -> Self {
Self::Iterator(func)
}
}
impl From<ScriptFnDef> for CallableFunction {
fn from(_func: ScriptFnDef) -> Self {
#[cfg(feature = "no_function")]
unreachable!();
#[cfg(not(feature = "no_function"))]
Self::Script(_func.into())
}
}
impl From<Shared<ScriptFnDef>> for CallableFunction {
fn from(_func: Shared<ScriptFnDef>) -> Self {
#[cfg(feature = "no_function")]
unreachable!();
#[cfg(not(feature = "no_function"))]
Self::Script(_func)
}
}