Skip to main content

rhai/func/
native.rs

1//! Module defining interfaces to native-Rust functions.
2
3use super::call::FnCallArgs;
4use crate::ast::FnCallHashes;
5use crate::eval::{Caches, GlobalRuntimeState};
6use crate::plugin::PluginFunc;
7use crate::tokenizer::{is_valid_function_name, Token, TokenizeState};
8use crate::types::dynamic::Variant;
9use crate::{
10    calc_fn_hash, expose_under_internals, Dynamic, Engine, EvalContext, FnArgsVec, FuncArgs,
11    Position, RhaiResult, RhaiResultOf, StaticVec, VarDefInfo, ERR,
12};
13use std::any::type_name;
14#[cfg(feature = "no_std")]
15use std::prelude::v1::*;
16
17/// Trait that maps to `Send + Sync` only under the `sync` feature.
18#[cfg(feature = "sync")]
19pub trait SendSync: Send + Sync {}
20/// Trait that maps to `Send + Sync` only under the `sync` feature.
21#[cfg(feature = "sync")]
22impl<T: Send + Sync> SendSync for T {}
23
24/// Trait that maps to `Send + Sync` only under the `sync` feature.
25#[cfg(not(feature = "sync"))]
26pub trait SendSync {}
27/// Trait that maps to `Send + Sync` only under the `sync` feature.
28#[cfg(not(feature = "sync"))]
29impl<T> SendSync for T {}
30
31/// Immutable reference-counted container.
32#[cfg(not(feature = "sync"))]
33// TODO: Further audit no_std compatibility
34// When building with no_std + sync features, explicit imports from alloc
35// are needed despite using no_std_compat. This fixed compilation errors
36// around missing trait implementations for some users.
37pub use alloc::rc::Rc as Shared;
38/// Immutable reference-counted container.
39#[cfg(feature = "sync")]
40// TODO: Further audit no_std compatibility
41// While no_std_compat should map std::sync::Arc to alloc::sync::Arc,
42// there appear to be cases where this mapping fails.
43pub use alloc::sync::Arc as Shared;
44
45/// Synchronized shared object.
46#[cfg(not(feature = "sync"))]
47pub use std::cell::RefCell as Locked;
48
49/// Read-only lock guard for synchronized shared object.
50#[cfg(not(feature = "sync"))]
51pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
52
53/// Mutable lock guard for synchronized shared object.
54#[cfg(not(feature = "sync"))]
55pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
56
57/// Synchronized shared object.
58#[cfg(feature = "sync")]
59#[allow(dead_code)]
60pub use std::sync::RwLock as Locked;
61
62/// Read-only lock guard for synchronized shared object.
63#[cfg(feature = "sync")]
64#[allow(dead_code)]
65pub type LockGuard<'a, T> = std::sync::RwLockReadGuard<'a, T>;
66
67/// Mutable lock guard for synchronized shared object.
68#[cfg(feature = "sync")]
69#[allow(dead_code)]
70pub type LockGuardMut<'a, T> = std::sync::RwLockWriteGuard<'a, T>;
71
72/// Context of a native Rust function call.
73#[derive(Debug)]
74pub struct NativeCallContext<'a> {
75    /// The current [`Engine`].
76    engine: &'a Engine,
77    /// Name of function called.
78    fn_name: &'a str,
79    /// Function source, if any.
80    source: Option<&'a str>,
81    /// The current [`GlobalRuntimeState`], if any.
82    global: &'a GlobalRuntimeState,
83    /// [Position] of the function call.
84    pos: Position,
85}
86
87/// _(internals)_ Context of a native Rust function call, intended for persistence.
88/// Exported under the `internals` feature only.
89///
90/// # WARNING - Volatile Type
91///
92/// This type is volatile and may change in the future.
93#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
94#[cfg(feature = "internals")]
95#[derive(Debug, Clone)]
96pub struct NativeCallContextStore {
97    /// Name of function called.
98    pub fn_name: String,
99    /// Function source, if any.
100    pub source: Option<String>,
101    /// The current [`GlobalRuntimeState`], if any.
102    pub global: GlobalRuntimeState,
103    /// [Position] of the function call.
104    pub pos: Position,
105}
106
107#[cfg(feature = "internals")]
108#[allow(deprecated)]
109impl NativeCallContextStore {
110    /// Create a [`NativeCallContext`] from a [`NativeCallContextStore`].
111    ///
112    /// # WARNING - Unstable API
113    ///
114    /// This API is volatile and may change in the future.
115    #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
116    #[inline(always)]
117    #[must_use]
118    pub fn create_context<'a>(&'a self, engine: &'a Engine) -> NativeCallContext<'a> {
119        NativeCallContext::from_stored_data(engine, self)
120    }
121}
122
123impl<'a>
124    From<(
125        &'a Engine,
126        &'a str,
127        Option<&'a str>,
128        &'a GlobalRuntimeState,
129        Position,
130    )> for NativeCallContext<'a>
131{
132    #[inline(always)]
133    fn from(
134        value: (
135            &'a Engine,
136            &'a str,
137            Option<&'a str>,
138            &'a GlobalRuntimeState,
139            Position,
140        ),
141    ) -> Self {
142        Self {
143            engine: value.0,
144            fn_name: value.1,
145            source: value.2,
146            global: value.3,
147            pos: value.4,
148        }
149    }
150}
151
152impl<'a> NativeCallContext<'a> {
153    /// _(internals)_ Create a new [`NativeCallContext`].
154    /// Exported under the `internals` feature only.
155    ///
156    /// Not available under `no_module`.
157    #[cfg(feature = "internals")]
158    #[cfg(not(feature = "no_module"))]
159    #[inline(always)]
160    #[must_use]
161    pub const fn new_with_all_fields(
162        engine: &'a Engine,
163        fn_name: &'a str,
164        source: Option<&'a str>,
165        global: &'a GlobalRuntimeState,
166        pos: Position,
167    ) -> Self {
168        Self {
169            engine,
170            fn_name,
171            source,
172            global,
173            pos,
174        }
175    }
176
177    /// _(internals)_ Create a [`NativeCallContext`] from a [`NativeCallContextStore`].
178    /// Exported under the `internals` feature only.
179    ///
180    /// # WARNING - Unstable API
181    ///
182    /// This API is volatile and may change in the future.
183    #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
184    #[cfg(feature = "internals")]
185    #[inline]
186    #[must_use]
187    #[allow(deprecated)]
188    pub fn from_stored_data(engine: &'a Engine, context: &'a NativeCallContextStore) -> Self {
189        Self {
190            engine,
191            fn_name: &context.fn_name,
192            source: context.source.as_deref(),
193            global: &context.global,
194            pos: context.pos,
195        }
196    }
197    /// _(internals)_ Store this [`NativeCallContext`] into a [`NativeCallContextStore`].
198    /// Exported under the `internals` feature only.
199    ///
200    /// # WARNING - Unstable API
201    ///
202    /// This API is volatile and may change in the future.
203    #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
204    #[cfg(feature = "internals")]
205    #[inline]
206    #[must_use]
207    #[allow(deprecated)]
208    pub fn store_data(&self) -> NativeCallContextStore {
209        NativeCallContextStore {
210            fn_name: self.fn_name.to_string(),
211            source: self.source.map(ToString::to_string),
212            global: self.global.clone(),
213            pos: self.pos,
214        }
215    }
216
217    /// The current [`Engine`].
218    #[inline(always)]
219    #[must_use]
220    pub const fn engine(&self) -> &Engine {
221        self.engine
222    }
223    /// Name of the function called.
224    #[inline(always)]
225    #[must_use]
226    pub const fn fn_name(&self) -> &str {
227        self.fn_name
228    }
229    /// Source of the function.
230    #[inline(always)]
231    #[must_use]
232    pub const fn fn_source(&self) -> Option<&str> {
233        self.source
234    }
235    /// Source of the caller.
236    #[inline(always)]
237    #[must_use]
238    pub fn call_source(&self) -> Option<&str> {
239        self.global.source.as_deref()
240    }
241    /// [Position] of the function call in the caller.
242    #[inline(always)]
243    #[must_use]
244    pub const fn call_position(&self) -> Position {
245        self.pos
246    }
247    /// Current nesting level of function calls.
248    #[inline(always)]
249    #[must_use]
250    pub const fn call_level(&self) -> usize {
251        self.global.level
252    }
253    /// Custom state kept in a [`Dynamic`].
254    #[inline(always)]
255    #[must_use]
256    pub const fn tag(&self) -> Option<&Dynamic> {
257        Some(&self.global.tag)
258    }
259    /// Get an iterator over the current set of modules imported via `import` statements in reverse order
260    /// (i.e. modules imported last come first).
261    ///
262    /// Not available under `no_module`.
263    #[cfg(not(feature = "no_module"))]
264    #[inline]
265    pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
266        self.global.iter_imports()
267    }
268    /// Get an iterator over the namespaces containing definitions of all script-defined functions.
269    ///
270    /// Not available under `no_function`.
271    #[cfg(not(feature = "no_function"))]
272    #[inline]
273    pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
274        self.global.lib.iter().map(<_>::as_ref)
275    }
276    /// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
277    /// Exported under the `internals` feature only.
278    ///
279    /// Not available under `no_function`.
280    #[cfg(not(feature = "no_function"))]
281    #[cfg(feature = "internals")]
282    #[inline(always)]
283    #[must_use]
284    pub fn namespaces(&self) -> &[crate::SharedModule] {
285        &self.global.lib
286    }
287    /// _(internals)_ The current [`GlobalRuntimeState`], if any.
288    /// Exported under the `internals` feature only.
289    ///
290    /// Not available under `no_module`.
291    #[expose_under_internals]
292    #[inline(always)]
293    #[must_use]
294    const fn global_runtime_state(&self) -> &GlobalRuntimeState {
295        self.global
296    }
297    /// _(internals, debugging)_ Debugging interface.
298    /// Exported under the `debugging` and `internals` features only.
299    #[cfg(feature = "debugging")]
300    #[cfg(feature = "internals")]
301    #[inline(always)]
302    #[must_use]
303    pub fn debugger(&self) -> Option<&crate::debugger::Debugger> {
304        self.global.debugger.as_deref()
305    }
306
307    /// Call a function inside the call context with the provided arguments.
308    #[inline]
309    pub fn call_fn<T: Variant + Clone>(
310        &self,
311        fn_name: impl AsRef<str>,
312        args: impl FuncArgs,
313    ) -> RhaiResultOf<T> {
314        let mut arg_values = StaticVec::new_const();
315        args.parse(&mut arg_values);
316
317        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
318
319        self._call_fn_raw(fn_name, args, false, false, false)
320            .and_then(|result| {
321                result.try_cast_result().map_err(|r| {
322                    let result_type = self.engine().map_type_name(r.type_name());
323                    let cast_type = match type_name::<T>() {
324                        typ if typ.contains("::") => self.engine.map_type_name(typ),
325                        typ => typ,
326                    };
327                    ERR::ErrorMismatchOutputType(
328                        cast_type.into(),
329                        result_type.into(),
330                        self.call_position(),
331                    )
332                    .into()
333                })
334            })
335    }
336    /// Call a function as a _method_ call inside the call context with the provided arguments
337    /// and a bound `this` pointer.
338    ///
339    /// Not available under `no_object`.
340    #[cfg(not(feature = "no_object"))]
341    #[inline]
342    pub fn call_method<T: Variant + Clone>(
343        &self,
344        fn_name: impl AsRef<str>,
345        this_ptr: &mut Dynamic,
346        args: impl FuncArgs,
347    ) -> RhaiResultOf<T> {
348        let mut arg_values = StaticVec::new_const();
349        args.parse(&mut arg_values);
350
351        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
352        args.insert(0, this_ptr);
353
354        self._call_fn_raw(fn_name, args, false, true, true)
355            .and_then(|result| {
356                result.try_cast_result().map_err(|r| {
357                    let result_type = self.engine().map_type_name(r.type_name());
358                    let cast_type = match type_name::<T>() {
359                        typ if typ.contains("::") => self.engine.map_type_name(typ),
360                        typ => typ,
361                    };
362                    ERR::ErrorMismatchOutputType(
363                        cast_type.into(),
364                        result_type.into(),
365                        self.call_position(),
366                    )
367                    .into()
368                })
369            })
370    }
371    /// Call a registered native Rust function inside the call context with the provided arguments.
372    ///
373    /// This is often useful because Rust functions typically only want to cross-call other
374    /// registered Rust functions and not have to worry about scripted functions hijacking the
375    /// process unknowingly (or deliberately).
376    #[inline]
377    pub fn call_native_fn<T: Variant + Clone>(
378        &self,
379        fn_name: impl AsRef<str>,
380        args: impl FuncArgs,
381    ) -> RhaiResultOf<T> {
382        let mut arg_values = StaticVec::new_const();
383        args.parse(&mut arg_values);
384
385        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
386
387        self._call_fn_raw(fn_name, args, true, false, false)
388            .and_then(|result| {
389                result.try_cast_result().map_err(|r| {
390                    let result_type = self.engine().map_type_name(r.type_name());
391                    let cast_type = match type_name::<T>() {
392                        typ if typ.contains("::") => self.engine.map_type_name(typ),
393                        typ => typ,
394                    };
395                    ERR::ErrorMismatchOutputType(
396                        cast_type.into(),
397                        result_type.into(),
398                        self.call_position(),
399                    )
400                    .into()
401                })
402            })
403    }
404    /// Call a registered native Rust function as a _method_ call inside the call context with the provided arguments
405    /// and a bound object.
406    ///
407    /// Not available under `no_object`.
408    ///
409    /// This is often useful because Rust functions typically only want to cross-call other
410    /// registered Rust functions and not have to worry about scripted functions hijacking the
411    /// process unknowingly (or deliberately).
412    #[cfg(not(feature = "no_object"))]
413    #[inline]
414    pub fn call_native_method<T: Variant + Clone>(
415        &self,
416        fn_name: impl AsRef<str>,
417        object: &mut Dynamic,
418        args: impl FuncArgs,
419    ) -> RhaiResultOf<T> {
420        let mut arg_values = StaticVec::new_const();
421        args.parse(&mut arg_values);
422
423        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
424        args.insert(0, object);
425
426        self._call_fn_raw(fn_name, args, true, true, true)
427            .and_then(|result| {
428                result.try_cast_result().map_err(|r| {
429                    let result_type = self.engine().map_type_name(r.type_name());
430                    let cast_type = match type_name::<T>() {
431                        typ if typ.contains("::") => self.engine.map_type_name(typ),
432                        typ => typ,
433                    };
434                    ERR::ErrorMismatchOutputType(
435                        cast_type.into(),
436                        result_type.into(),
437                        self.call_position(),
438                    )
439                    .into()
440                })
441            })
442    }
443    /// Call a function (native Rust or scripted) inside the call context.
444    ///
445    /// If `is_method_call` is [`true`], the first argument is assumed to be the `this` pointer for
446    /// a script-defined function (or the object of a method call).
447    ///
448    /// # WARNING - Low Level API
449    ///
450    /// This function is very low level.
451    ///
452    /// # Arguments
453    ///
454    /// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
455    /// unnecessarily cloning the arguments.
456    ///
457    /// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
458    /// _before_ calling this function.
459    ///
460    /// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
461    /// not consumed.
462    #[inline(always)]
463    pub fn call_fn_raw(
464        &self,
465        fn_name: impl AsRef<str>,
466        is_ref_mut: bool,
467        is_method_call: bool,
468        args: &mut [&mut Dynamic],
469    ) -> RhaiResult {
470        let name = fn_name.as_ref();
471        let native_only = !is_valid_function_name(name);
472        #[cfg(not(feature = "no_function"))]
473        let native_only = native_only && !crate::parser::is_anonymous_fn(name);
474
475        self._call_fn_raw(fn_name, args, native_only, is_ref_mut, is_method_call)
476    }
477    /// Call a registered native Rust function inside the call context.
478    ///
479    /// This is often useful because Rust functions typically only want to cross-call other
480    /// registered Rust functions and not have to worry about scripted functions hijacking the
481    /// process unknowingly (or deliberately).
482    ///
483    /// # WARNING - Low Level API
484    ///
485    /// This function is very low level.
486    ///
487    /// # Arguments
488    ///
489    /// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
490    /// unnecessarily cloning the arguments.
491    ///
492    /// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
493    /// _before_ calling this function.
494    ///
495    /// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
496    /// not consumed.
497    #[inline(always)]
498    pub fn call_native_fn_raw(
499        &self,
500        fn_name: impl AsRef<str>,
501        is_ref_mut: bool,
502        args: &mut [&mut Dynamic],
503    ) -> RhaiResult {
504        self._call_fn_raw(fn_name, args, true, is_ref_mut, false)
505    }
506
507    /// Call a function (native Rust or scripted) inside the call context.
508    fn _call_fn_raw(
509        &self,
510        fn_name: impl AsRef<str>,
511        args: &mut [&mut Dynamic],
512        native_only: bool,
513        is_ref_mut: bool,
514        is_method_call: bool,
515    ) -> RhaiResult {
516        let global = &mut self.global.clone();
517        global.level += 1;
518
519        let caches = &mut Caches::new();
520
521        let fn_name = fn_name.as_ref();
522        let op_token = Token::lookup_symbol_from_syntax(fn_name);
523        let args_len = args.len();
524
525        if native_only {
526            return self
527                .engine()
528                .exec_native_fn_call(
529                    global,
530                    caches,
531                    fn_name,
532                    op_token.as_ref(),
533                    calc_fn_hash(None, fn_name, args_len),
534                    args,
535                    is_ref_mut,
536                    false,
537                    self.call_position(),
538                )
539                .map(|(r, ..)| r);
540        }
541
542        // Native or script
543
544        let hash = match is_method_call {
545            #[cfg(not(feature = "no_function"))]
546            true => FnCallHashes::from_script_and_native(
547                calc_fn_hash(None, fn_name, args_len - 1),
548                calc_fn_hash(None, fn_name, args_len),
549            ),
550            #[cfg(feature = "no_function")]
551            true => FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args_len)),
552            _ => FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args_len)),
553        };
554
555        self.engine()
556            .exec_fn_call(
557                global,
558                caches,
559                None,
560                fn_name,
561                op_token.as_ref(),
562                hash,
563                args,
564                is_ref_mut,
565                is_method_call,
566                self.call_position(),
567            )
568            .map(|(r, ..)| r)
569    }
570}
571
572/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
573/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
574#[inline(always)]
575#[must_use]
576#[allow(dead_code)]
577pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
578    Shared::make_mut(value)
579}
580
581/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
582#[inline(always)]
583#[must_use]
584#[allow(dead_code)]
585pub fn shared_get_mut<T: Clone>(value: &mut Shared<T>) -> Option<&mut T> {
586    Shared::get_mut(value)
587}
588
589/// Consume a [`Shared`] resource if is unique (i.e. not shared), or clone it otherwise.
590#[inline]
591#[must_use]
592#[allow(dead_code)]
593pub fn shared_take_or_clone<T: Clone>(value: Shared<T>) -> T {
594    shared_try_take(value).unwrap_or_else(|v| v.as_ref().clone())
595}
596
597/// Consume a [`Shared`] resource if is unique (i.e. not shared).
598#[inline(always)]
599#[allow(dead_code)]
600pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
601    Shared::try_unwrap(value)
602}
603
604/// Consume a [`Shared`] resource, assuming that it is unique (i.e. not shared).
605///
606/// # Panics
607///
608/// Panics if the resource is shared (i.e. has other outstanding references).
609#[inline]
610#[must_use]
611#[allow(dead_code)]
612pub fn shared_take<T>(value: Shared<T>) -> T {
613    shared_try_take(value)
614        .ok()
615        .unwrap_or_else(|| panic!("`value` is shared (i.e. has outstanding references)"))
616}
617
618/// _(internals)_ Lock a [`Locked`] resource for immutable access.
619/// Exported under the `internals` feature only.
620#[inline(always)]
621#[must_use]
622#[allow(dead_code)]
623pub fn locked_read<T>(value: &Locked<T>) -> Option<LockGuard<'_, T>> {
624    #[cfg(not(feature = "sync"))]
625    return value.try_borrow().ok();
626
627    #[cfg(feature = "sync")]
628    #[cfg(not(feature = "no_std"))]
629    {
630        #[cfg(feature = "unchecked")]
631        return value.read().ok();
632
633        #[cfg(not(feature = "unchecked"))]
634        {
635            // Spin-lock for a short while before giving up
636            for _ in 0..5 {
637                match value.try_read() {
638                    Ok(guard) => return Some(guard),
639                    Err(std::sync::TryLockError::WouldBlock) => {
640                        std::thread::sleep(std::time::Duration::from_millis(10))
641                    }
642                    Err(_) => return None,
643                }
644            }
645
646            return None;
647        }
648    }
649
650    #[cfg(feature = "sync")]
651    #[cfg(feature = "no_std")]
652    {
653        #[cfg(feature = "unchecked")]
654        return Some(value.read());
655        #[cfg(not(feature = "unchecked"))]
656        return value.try_read();
657    }
658}
659
660/// _(internals)_ Lock a [`Locked`] resource for mutable access.
661/// Exported under the `internals` feature only.
662#[inline(always)]
663#[must_use]
664#[allow(dead_code)]
665pub fn locked_write<T>(value: &Locked<T>) -> Option<LockGuardMut<'_, T>> {
666    #[cfg(not(feature = "sync"))]
667    return value.try_borrow_mut().ok();
668
669    #[cfg(feature = "sync")]
670    #[cfg(not(feature = "no_std"))]
671    {
672        #[cfg(feature = "unchecked")]
673        return value.write().ok();
674
675        #[cfg(not(feature = "unchecked"))]
676        {
677            // Spin-lock for a short while before giving up
678            for _ in 0..5 {
679                match value.try_write() {
680                    Ok(guard) => return Some(guard),
681                    Err(std::sync::TryLockError::WouldBlock) => {
682                        std::thread::sleep(std::time::Duration::from_millis(10))
683                    }
684                    Err(_) => return None,
685                }
686            }
687
688            return None;
689        }
690    }
691
692    #[cfg(feature = "sync")]
693    #[cfg(feature = "no_std")]
694    {
695        #[cfg(feature = "unchecked")]
696        return Some(value.write());
697        #[cfg(not(feature = "unchecked"))]
698        return value.try_write();
699    }
700}
701
702/// General Rust function trait object.
703#[cfg(not(feature = "sync"))]
704pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult;
705/// General Rust function trait object.
706#[cfg(feature = "sync")]
707pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult + Send + Sync;
708
709/// Built-in function trait object.
710pub type FnBuiltin = (
711    fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult,
712    bool,
713);
714
715/// Function that gets an iterator from a type.
716#[cfg(not(feature = "sync"))]
717pub type FnIterator = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>;
718/// Function that gets an iterator from a type.
719#[cfg(feature = "sync")]
720pub type FnIterator =
721    dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + Send + Sync;
722
723/// Plugin function trait object.
724#[cfg(not(feature = "sync"))]
725pub type FnPlugin = dyn PluginFunc;
726/// Plugin function trait object.
727#[cfg(feature = "sync")]
728pub type FnPlugin = dyn PluginFunc + Send + Sync;
729
730/// Callback function for progress reporting.
731#[cfg(not(feature = "unchecked"))]
732#[cfg(not(feature = "sync"))]
733pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic>;
734/// Callback function for progress reporting.
735#[cfg(not(feature = "unchecked"))]
736#[cfg(feature = "sync")]
737pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic> + Send + Sync;
738
739/// Callback function for printing.
740#[cfg(not(feature = "sync"))]
741pub type OnPrintCallback = dyn Fn(&str);
742/// Callback function for printing.
743#[cfg(feature = "sync")]
744pub type OnPrintCallback = dyn Fn(&str) + Send + Sync;
745
746/// Callback function for debugging.
747#[cfg(not(feature = "sync"))]
748pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position);
749/// Callback function for debugging.
750#[cfg(feature = "sync")]
751pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync;
752
753/// _(internals)_ Callback function when a property accessed is not found in a [`Map`][crate::Map].
754/// Exported under the `internals` feature only.
755#[cfg(not(feature = "sync"))]
756#[cfg(not(feature = "no_index"))]
757#[cfg(feature = "internals")]
758pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(
759    &'a mut crate::Array,
760    crate::INT,
761    EvalContext,
762) -> RhaiResultOf<crate::Target<'a>>;
763/// Callback function when a property accessed is not found in a [`Map`][crate::Map].
764/// Exported under the `internals` feature only.
765#[cfg(feature = "sync")]
766#[cfg(not(feature = "no_index"))]
767#[cfg(feature = "internals")]
768pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(&'a mut crate::Array, crate::INT, EvalContext) -> RhaiResultOf<crate::Target<'a>>
769    + Send
770    + Sync;
771
772/// _(internals)_ Callback function when a property accessed is not found in a [`Map`][crate::Map].
773/// Exported under the `internals` feature only.
774#[cfg(not(feature = "sync"))]
775#[cfg(not(feature = "no_object"))]
776#[cfg(feature = "internals")]
777pub type OnMissingMapPropertyCallback =
778    dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf<crate::eval::Target<'a>>;
779/// Callback function when a property accessed is not found in a [`Map`][crate::Map].
780/// Exported under the `internals` feature only.
781#[cfg(feature = "sync")]
782#[cfg(not(feature = "no_object"))]
783#[cfg(feature = "internals")]
784pub type OnMissingMapPropertyCallback = dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf<crate::eval::Target<'a>>
785    + Send
786    + Sync;
787
788/// _(internals)_ Callback function when a function call is not found.
789/// Exported under the `internals` feature only.
790///
791/// Not triggered for qualified function calls (e.g. `module::function()`).
792#[cfg(not(feature = "sync"))]
793#[cfg(feature = "internals")]
794pub type OnMissingFunctionCallback =
795    dyn Fn(&str, &mut [&mut Dynamic], bool, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
796/// _(internals)_ Callback function when a function call is not found.
797/// Exported under the `internals` feature only.
798///
799/// Not triggered for qualified function calls (e.g. `module::function()`).
800#[cfg(feature = "sync")]
801#[cfg(feature = "internals")]
802pub type OnMissingFunctionCallback = dyn Fn(&str, &mut [&mut Dynamic], bool, EvalContext) -> RhaiResultOf<Option<Dynamic>>
803    + Send
804    + Sync;
805
806/// Callback function for mapping tokens during parsing.
807#[cfg(not(feature = "sync"))]
808pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token;
809/// Callback function for mapping tokens during parsing.
810#[cfg(feature = "sync")]
811pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token + Send + Sync;
812
813/// Callback function for variable access.
814#[cfg(not(feature = "sync"))]
815pub type OnVarCallback = dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
816/// Callback function for variable access.
817#[cfg(feature = "sync")]
818pub type OnVarCallback =
819    dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>> + Send + Sync;
820
821/// Callback function for variable definition.
822#[cfg(not(feature = "sync"))]
823pub type OnDefVarCallback = dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool>;
824/// Callback function for variable definition.
825#[cfg(feature = "sync")]
826pub type OnDefVarCallback =
827    dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool> + Send + Sync;