1use 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#[cfg(feature = "sync")]
19pub trait SendSync: Send + Sync {}
20#[cfg(feature = "sync")]
22impl<T: Send + Sync> SendSync for T {}
23
24#[cfg(not(feature = "sync"))]
26pub trait SendSync {}
27#[cfg(not(feature = "sync"))]
29impl<T> SendSync for T {}
30
31#[cfg(not(feature = "sync"))]
33pub use alloc::rc::Rc as Shared;
38#[cfg(feature = "sync")]
40pub use alloc::sync::Arc as Shared;
44
45#[cfg(not(feature = "sync"))]
47pub use std::cell::RefCell as Locked;
48
49#[cfg(not(feature = "sync"))]
51pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
52
53#[cfg(not(feature = "sync"))]
55pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
56
57#[cfg(feature = "sync")]
59#[allow(dead_code)]
60pub use std::sync::RwLock as Locked;
61
62#[cfg(feature = "sync")]
64#[allow(dead_code)]
65pub type LockGuard<'a, T> = std::sync::RwLockReadGuard<'a, T>;
66
67#[cfg(feature = "sync")]
69#[allow(dead_code)]
70pub type LockGuardMut<'a, T> = std::sync::RwLockWriteGuard<'a, T>;
71
72#[derive(Debug)]
74pub struct NativeCallContext<'a> {
75 engine: &'a Engine,
77 fn_name: &'a str,
79 source: Option<&'a str>,
81 global: &'a GlobalRuntimeState,
83 pos: Position,
85}
86
87#[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 pub fn_name: String,
99 pub source: Option<String>,
101 pub global: GlobalRuntimeState,
103 pub pos: Position,
105}
106
107#[cfg(feature = "internals")]
108#[allow(deprecated)]
109impl NativeCallContextStore {
110 #[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 #[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 #[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 #[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 #[inline(always)]
219 #[must_use]
220 pub const fn engine(&self) -> &Engine {
221 self.engine
222 }
223 #[inline(always)]
225 #[must_use]
226 pub const fn fn_name(&self) -> &str {
227 self.fn_name
228 }
229 #[inline(always)]
231 #[must_use]
232 pub const fn fn_source(&self) -> Option<&str> {
233 self.source
234 }
235 #[inline(always)]
237 #[must_use]
238 pub fn call_source(&self) -> Option<&str> {
239 self.global.source.as_deref()
240 }
241 #[inline(always)]
243 #[must_use]
244 pub const fn call_position(&self) -> Position {
245 self.pos
246 }
247 #[inline(always)]
249 #[must_use]
250 pub const fn call_level(&self) -> usize {
251 self.global.level
252 }
253 #[inline(always)]
255 #[must_use]
256 pub const fn tag(&self) -> Option<&Dynamic> {
257 Some(&self.global.tag)
258 }
259 #[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 #[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 #[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 #[expose_under_internals]
292 #[inline(always)]
293 #[must_use]
294 const fn global_runtime_state(&self) -> &GlobalRuntimeState {
295 self.global
296 }
297 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 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#[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#[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#[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#[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#[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#[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 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#[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 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#[cfg(not(feature = "sync"))]
704pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult;
705#[cfg(feature = "sync")]
707pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult + Send + Sync;
708
709pub type FnBuiltin = (
711 fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult,
712 bool,
713);
714
715#[cfg(not(feature = "sync"))]
717pub type FnIterator = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>;
718#[cfg(feature = "sync")]
720pub type FnIterator =
721 dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + Send + Sync;
722
723#[cfg(not(feature = "sync"))]
725pub type FnPlugin = dyn PluginFunc;
726#[cfg(feature = "sync")]
728pub type FnPlugin = dyn PluginFunc + Send + Sync;
729
730#[cfg(not(feature = "unchecked"))]
732#[cfg(not(feature = "sync"))]
733pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic>;
734#[cfg(not(feature = "unchecked"))]
736#[cfg(feature = "sync")]
737pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic> + Send + Sync;
738
739#[cfg(not(feature = "sync"))]
741pub type OnPrintCallback = dyn Fn(&str);
742#[cfg(feature = "sync")]
744pub type OnPrintCallback = dyn Fn(&str) + Send + Sync;
745
746#[cfg(not(feature = "sync"))]
748pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position);
749#[cfg(feature = "sync")]
751pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync;
752
753#[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#[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#[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#[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#[cfg(not(feature = "sync"))]
793#[cfg(feature = "internals")]
794pub type OnMissingFunctionCallback =
795 dyn Fn(&str, &mut [&mut Dynamic], bool, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
796#[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#[cfg(not(feature = "sync"))]
808pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token;
809#[cfg(feature = "sync")]
811pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token + Send + Sync;
812
813#[cfg(not(feature = "sync"))]
815pub type OnVarCallback = dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
816#[cfg(feature = "sync")]
818pub type OnVarCallback =
819 dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>> + Send + Sync;
820
821#[cfg(not(feature = "sync"))]
823pub type OnDefVarCallback = dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool>;
824#[cfg(feature = "sync")]
826pub type OnDefVarCallback =
827 dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool> + Send + Sync;