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
260    /// in reverse order.
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    /// _(internals)_ The current [`GlobalRuntimeState`], if any.
269    /// Exported under the `internals` feature only.
270    ///
271    /// Not available under `no_module`.
272    #[expose_under_internals]
273    #[inline(always)]
274    #[must_use]
275    const fn global_runtime_state(&self) -> &GlobalRuntimeState {
276        self.global
277    }
278    /// Get an iterator over the namespaces containing definitions of all script-defined functions
279    /// in reverse order (i.e. parent namespaces are iterated after child namespaces).
280    ///
281    /// Not available under `no_function`.
282    #[cfg(not(feature = "no_function"))]
283    #[inline]
284    pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
285        self.global.lib.iter().map(<_>::as_ref)
286    }
287    /// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions.
288    /// Exported under the `internals` feature only.
289    ///
290    /// Not available under `no_function`.
291    #[cfg(not(feature = "no_function"))]
292    #[cfg(feature = "internals")]
293    #[inline(always)]
294    #[must_use]
295    pub fn namespaces(&self) -> &[crate::SharedModule] {
296        &self.global.lib
297    }
298    /// Call a function inside the call context with the provided arguments.
299    #[inline]
300    pub fn call_fn<T: Variant + Clone>(
301        &self,
302        fn_name: impl AsRef<str>,
303        args: impl FuncArgs,
304    ) -> RhaiResultOf<T> {
305        let mut arg_values = StaticVec::new_const();
306        args.parse(&mut arg_values);
307
308        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
309
310        self._call_fn_raw(fn_name, args, false, false, false)
311            .and_then(|result| {
312                result.try_cast_result().map_err(|r| {
313                    let result_type = self.engine().map_type_name(r.type_name());
314                    let cast_type = match type_name::<T>() {
315                        typ if typ.contains("::") => self.engine.map_type_name(typ),
316                        typ => typ,
317                    };
318                    ERR::ErrorMismatchOutputType(
319                        cast_type.into(),
320                        result_type.into(),
321                        self.call_position(),
322                    )
323                    .into()
324                })
325            })
326    }
327    /// Call a registered native Rust function inside the call context with the provided arguments.
328    ///
329    /// This is often useful because Rust functions typically only want to cross-call other
330    /// registered Rust functions and not have to worry about scripted functions hijacking the
331    /// process unknowingly (or deliberately).
332    #[inline]
333    pub fn call_native_fn<T: Variant + Clone>(
334        &self,
335        fn_name: impl AsRef<str>,
336        args: impl FuncArgs,
337    ) -> RhaiResultOf<T> {
338        let mut arg_values = StaticVec::new_const();
339        args.parse(&mut arg_values);
340
341        let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
342
343        self._call_fn_raw(fn_name, args, true, false, false)
344            .and_then(|result| {
345                result.try_cast_result().map_err(|r| {
346                    let result_type = self.engine().map_type_name(r.type_name());
347                    let cast_type = match type_name::<T>() {
348                        typ if typ.contains("::") => self.engine.map_type_name(typ),
349                        typ => typ,
350                    };
351                    ERR::ErrorMismatchOutputType(
352                        cast_type.into(),
353                        result_type.into(),
354                        self.call_position(),
355                    )
356                    .into()
357                })
358            })
359    }
360    /// Call a function (native Rust or scripted) inside the call context.
361    ///
362    /// If `is_method_call` is [`true`], the first argument is assumed to be the `this` pointer for
363    /// a script-defined function (or the object of a method call).
364    ///
365    /// # WARNING - Low Level API
366    ///
367    /// This function is very low level.
368    ///
369    /// # Arguments
370    ///
371    /// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
372    /// unnecessarily cloning the arguments.
373    ///
374    /// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
375    /// _before_ calling this function.
376    ///
377    /// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
378    /// not consumed.
379    #[inline(always)]
380    pub fn call_fn_raw(
381        &self,
382        fn_name: impl AsRef<str>,
383        is_ref_mut: bool,
384        is_method_call: bool,
385        args: &mut [&mut Dynamic],
386    ) -> RhaiResult {
387        let name = fn_name.as_ref();
388        let native_only = !is_valid_function_name(name);
389        #[cfg(not(feature = "no_function"))]
390        let native_only = native_only && !crate::parser::is_anonymous_fn(name);
391
392        self._call_fn_raw(fn_name, args, native_only, is_ref_mut, is_method_call)
393    }
394    /// Call a registered native Rust function inside the call context.
395    ///
396    /// This is often useful because Rust functions typically only want to cross-call other
397    /// registered Rust functions and not have to worry about scripted functions hijacking the
398    /// process unknowingly (or deliberately).
399    ///
400    /// # WARNING - Low Level API
401    ///
402    /// This function is very low level.
403    ///
404    /// # Arguments
405    ///
406    /// All arguments may be _consumed_, meaning that they may be replaced by `()`. This is to avoid
407    /// unnecessarily cloning the arguments.
408    ///
409    /// **DO NOT** reuse the arguments after this call. If they are needed afterwards, clone them
410    /// _before_ calling this function.
411    ///
412    /// If `is_ref_mut` is [`true`], the first argument is assumed to be passed by reference and is
413    /// not consumed.
414    #[inline(always)]
415    pub fn call_native_fn_raw(
416        &self,
417        fn_name: impl AsRef<str>,
418        is_ref_mut: bool,
419        args: &mut [&mut Dynamic],
420    ) -> RhaiResult {
421        self._call_fn_raw(fn_name, args, true, is_ref_mut, false)
422    }
423
424    /// Call a function (native Rust or scripted) inside the call context.
425    fn _call_fn_raw(
426        &self,
427        fn_name: impl AsRef<str>,
428        args: &mut [&mut Dynamic],
429        native_only: bool,
430        is_ref_mut: bool,
431        is_method_call: bool,
432    ) -> RhaiResult {
433        let global = &mut self.global.clone();
434        global.level += 1;
435
436        let caches = &mut Caches::new();
437
438        let fn_name = fn_name.as_ref();
439        let op_token = Token::lookup_symbol_from_syntax(fn_name);
440        let args_len = args.len();
441
442        if native_only {
443            return self
444                .engine()
445                .exec_native_fn_call(
446                    global,
447                    caches,
448                    fn_name,
449                    op_token.as_ref(),
450                    calc_fn_hash(None, fn_name, args_len),
451                    args,
452                    is_ref_mut,
453                    false,
454                    self.call_position(),
455                )
456                .map(|(r, ..)| r);
457        }
458
459        // Native or script
460
461        let hash = match is_method_call {
462            #[cfg(not(feature = "no_function"))]
463            true => FnCallHashes::from_script_and_native(
464                calc_fn_hash(None, fn_name, args_len - 1),
465                calc_fn_hash(None, fn_name, args_len),
466            ),
467            #[cfg(feature = "no_function")]
468            true => FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args_len)),
469            _ => FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args_len)),
470        };
471
472        self.engine()
473            .exec_fn_call(
474                global,
475                caches,
476                None,
477                fn_name,
478                op_token.as_ref(),
479                hash,
480                args,
481                is_ref_mut,
482                is_method_call,
483                self.call_position(),
484            )
485            .map(|(r, ..)| r)
486    }
487}
488
489/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
490/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
491#[inline(always)]
492#[must_use]
493#[allow(dead_code)]
494pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
495    Shared::make_mut(value)
496}
497
498/// Return a mutable reference to the wrapped value of a [`Shared`] resource.
499#[inline(always)]
500#[must_use]
501#[allow(dead_code)]
502pub fn shared_get_mut<T: Clone>(value: &mut Shared<T>) -> Option<&mut T> {
503    Shared::get_mut(value)
504}
505
506/// Consume a [`Shared`] resource if is unique (i.e. not shared), or clone it otherwise.
507#[inline]
508#[must_use]
509#[allow(dead_code)]
510pub fn shared_take_or_clone<T: Clone>(value: Shared<T>) -> T {
511    shared_try_take(value).unwrap_or_else(|v| v.as_ref().clone())
512}
513
514/// Consume a [`Shared`] resource if is unique (i.e. not shared).
515#[inline(always)]
516#[allow(dead_code)]
517pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
518    Shared::try_unwrap(value)
519}
520
521/// Consume a [`Shared`] resource, assuming that it is unique (i.e. not shared).
522///
523/// # Panics
524///
525/// Panics if the resource is shared (i.e. has other outstanding references).
526#[inline]
527#[must_use]
528#[allow(dead_code)]
529pub fn shared_take<T>(value: Shared<T>) -> T {
530    shared_try_take(value)
531        .ok()
532        .unwrap_or_else(|| panic!("`value` is shared (i.e. has outstanding references)"))
533}
534
535/// _(internals)_ Lock a [`Locked`] resource for immutable access.
536/// Exported under the `internals` feature only.
537#[inline(always)]
538#[must_use]
539#[allow(dead_code)]
540pub fn locked_read<T>(value: &Locked<T>) -> Option<LockGuard<'_, T>> {
541    #[cfg(not(feature = "sync"))]
542    return value.try_borrow().ok();
543
544    #[cfg(feature = "sync")]
545    #[cfg(not(feature = "no_std"))]
546    {
547        #[cfg(feature = "unchecked")]
548        return value.read().ok();
549
550        #[cfg(not(feature = "unchecked"))]
551        {
552            // Spin-lock for a short while before giving up
553            for _ in 0..5 {
554                match value.try_read() {
555                    Ok(guard) => return Some(guard),
556                    Err(std::sync::TryLockError::WouldBlock) => {
557                        std::thread::sleep(std::time::Duration::from_millis(10))
558                    }
559                    Err(_) => return None,
560                }
561            }
562
563            return None;
564        }
565    }
566
567    #[cfg(feature = "sync")]
568    #[cfg(feature = "no_std")]
569    {
570        #[cfg(feature = "unchecked")]
571        return Some(value.read());
572        #[cfg(not(feature = "unchecked"))]
573        return value.try_read();
574    }
575}
576
577/// _(internals)_ Lock a [`Locked`] resource for mutable access.
578/// Exported under the `internals` feature only.
579#[inline(always)]
580#[must_use]
581#[allow(dead_code)]
582pub fn locked_write<T>(value: &Locked<T>) -> Option<LockGuardMut<'_, T>> {
583    #[cfg(not(feature = "sync"))]
584    return value.try_borrow_mut().ok();
585
586    #[cfg(feature = "sync")]
587    #[cfg(not(feature = "no_std"))]
588    {
589        #[cfg(feature = "unchecked")]
590        return value.write().ok();
591
592        #[cfg(not(feature = "unchecked"))]
593        {
594            // Spin-lock for a short while before giving up
595            for _ in 0..5 {
596                match value.try_write() {
597                    Ok(guard) => return Some(guard),
598                    Err(std::sync::TryLockError::WouldBlock) => {
599                        std::thread::sleep(std::time::Duration::from_millis(10))
600                    }
601                    Err(_) => return None,
602                }
603            }
604
605            return None;
606        }
607    }
608
609    #[cfg(feature = "sync")]
610    #[cfg(feature = "no_std")]
611    {
612        #[cfg(feature = "unchecked")]
613        return Some(value.write());
614        #[cfg(not(feature = "unchecked"))]
615        return value.try_write();
616    }
617}
618
619/// General Rust function trait object.
620#[cfg(not(feature = "sync"))]
621pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult;
622/// General Rust function trait object.
623#[cfg(feature = "sync")]
624pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult + Send + Sync;
625
626/// Built-in function trait object.
627pub type FnBuiltin = (
628    fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult,
629    bool,
630);
631
632/// Function that gets an iterator from a type.
633#[cfg(not(feature = "sync"))]
634pub type FnIterator = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>;
635/// Function that gets an iterator from a type.
636#[cfg(feature = "sync")]
637pub type FnIterator =
638    dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + Send + Sync;
639
640/// Plugin function trait object.
641#[cfg(not(feature = "sync"))]
642pub type FnPlugin = dyn PluginFunc;
643/// Plugin function trait object.
644#[cfg(feature = "sync")]
645pub type FnPlugin = dyn PluginFunc + Send + Sync;
646
647/// Callback function for progress reporting.
648#[cfg(not(feature = "unchecked"))]
649#[cfg(not(feature = "sync"))]
650pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic>;
651/// Callback function for progress reporting.
652#[cfg(not(feature = "unchecked"))]
653#[cfg(feature = "sync")]
654pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic> + Send + Sync;
655
656/// Callback function for printing.
657#[cfg(not(feature = "sync"))]
658pub type OnPrintCallback = dyn Fn(&str);
659/// Callback function for printing.
660#[cfg(feature = "sync")]
661pub type OnPrintCallback = dyn Fn(&str) + Send + Sync;
662
663/// Callback function for debugging.
664#[cfg(not(feature = "sync"))]
665pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position);
666/// Callback function for debugging.
667#[cfg(feature = "sync")]
668pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync;
669
670/// _(internals)_ Callback function when a property accessed is not found in a [`Map`][crate::Map].
671/// Exported under the `internals` feature only.
672#[cfg(not(feature = "sync"))]
673#[cfg(not(feature = "no_index"))]
674#[cfg(feature = "internals")]
675pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(
676    &'a mut crate::Array,
677    crate::INT,
678    EvalContext,
679) -> RhaiResultOf<crate::Target<'a>>;
680/// Callback function when a property accessed is not found in a [`Map`][crate::Map].
681/// Exported under the `internals` feature only.
682#[cfg(feature = "sync")]
683#[cfg(not(feature = "no_index"))]
684#[cfg(feature = "internals")]
685pub type OnInvalidArrayIndexCallback = dyn for<'a> Fn(&'a mut crate::Array, crate::INT, EvalContext) -> RhaiResultOf<crate::Target<'a>>
686    + Send
687    + Sync;
688
689/// _(internals)_ Callback function when a property accessed is not found in a [`Map`][crate::Map].
690/// Exported under the `internals` feature only.
691#[cfg(not(feature = "sync"))]
692#[cfg(not(feature = "no_object"))]
693#[cfg(feature = "internals")]
694pub type OnMissingMapPropertyCallback =
695    dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf<crate::eval::Target<'a>>;
696/// Callback function when a property accessed is not found in a [`Map`][crate::Map].
697/// Exported under the `internals` feature only.
698#[cfg(feature = "sync")]
699#[cfg(not(feature = "no_object"))]
700#[cfg(feature = "internals")]
701pub type OnMissingMapPropertyCallback = dyn for<'a> Fn(&'a mut crate::Map, &str, EvalContext) -> RhaiResultOf<crate::eval::Target<'a>>
702    + Send
703    + Sync;
704
705/// Callback function for mapping tokens during parsing.
706#[cfg(not(feature = "sync"))]
707pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token;
708/// Callback function for mapping tokens during parsing.
709#[cfg(feature = "sync")]
710pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token + Send + Sync;
711
712/// Callback function for variable access.
713#[cfg(not(feature = "sync"))]
714pub type OnVarCallback = dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
715/// Callback function for variable access.
716#[cfg(feature = "sync")]
717pub type OnVarCallback =
718    dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>> + Send + Sync;
719
720/// Callback function for variable definition.
721#[cfg(not(feature = "sync"))]
722pub type OnDefVarCallback = dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool>;
723/// Callback function for variable definition.
724#[cfg(feature = "sync")]
725pub type OnDefVarCallback =
726    dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool> + Send + Sync;