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, Dynamic, Engine, EvalContext, FnArgsVec, FuncArgs, Position, RhaiResult,
11 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 std::rc::Rc as Shared;
34#[cfg(feature = "sync")]
36pub use std::sync::Arc as Shared;
37
38#[cfg(not(feature = "sync"))]
40pub use std::cell::RefCell as Locked;
41
42#[cfg(not(feature = "sync"))]
44pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
45
46#[cfg(not(feature = "sync"))]
48pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
49
50#[cfg(feature = "sync")]
52#[allow(dead_code)]
53pub use std::sync::RwLock as Locked;
54
55#[cfg(feature = "sync")]
57#[allow(dead_code)]
58pub type LockGuard<'a, T> = std::sync::RwLockReadGuard<'a, T>;
59
60#[cfg(feature = "sync")]
62#[allow(dead_code)]
63pub type LockGuardMut<'a, T> = std::sync::RwLockWriteGuard<'a, T>;
64
65#[derive(Debug)]
67pub struct NativeCallContext<'a> {
68 engine: &'a Engine,
70 fn_name: &'a str,
72 source: Option<&'a str>,
74 global: &'a GlobalRuntimeState,
76 pos: Position,
78}
79
80#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
87#[cfg(feature = "internals")]
88#[derive(Debug, Clone)]
89pub struct NativeCallContextStore {
90 pub fn_name: String,
92 pub source: Option<String>,
94 pub global: GlobalRuntimeState,
96 pub pos: Position,
98}
99
100#[cfg(feature = "internals")]
101#[allow(deprecated)]
102impl NativeCallContextStore {
103 #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
109 #[inline(always)]
110 #[must_use]
111 pub fn create_context<'a>(&'a self, engine: &'a Engine) -> NativeCallContext<'a> {
112 NativeCallContext::from_stored_data(engine, self)
113 }
114}
115
116impl<'a>
117 From<(
118 &'a Engine,
119 &'a str,
120 Option<&'a str>,
121 &'a GlobalRuntimeState,
122 Position,
123 )> for NativeCallContext<'a>
124{
125 #[inline(always)]
126 fn from(
127 value: (
128 &'a Engine,
129 &'a str,
130 Option<&'a str>,
131 &'a GlobalRuntimeState,
132 Position,
133 ),
134 ) -> Self {
135 Self {
136 engine: value.0,
137 fn_name: value.1,
138 source: value.2,
139 global: value.3,
140 pos: value.4,
141 }
142 }
143}
144
145impl<'a> NativeCallContext<'a> {
146 #[cfg(feature = "internals")]
151 #[cfg(not(feature = "no_module"))]
152 #[inline(always)]
153 #[must_use]
154 pub const fn new_with_all_fields(
155 engine: &'a Engine,
156 fn_name: &'a str,
157 source: Option<&'a str>,
158 global: &'a GlobalRuntimeState,
159 pos: Position,
160 ) -> Self {
161 Self {
162 engine,
163 fn_name,
164 source,
165 global,
166 pos,
167 }
168 }
169
170 #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
177 #[cfg(feature = "internals")]
178 #[inline]
179 #[must_use]
180 #[allow(deprecated)]
181 pub fn from_stored_data(engine: &'a Engine, context: &'a NativeCallContextStore) -> Self {
182 Self {
183 engine,
184 fn_name: &context.fn_name,
185 source: context.source.as_deref(),
186 global: &context.global,
187 pos: context.pos,
188 }
189 }
190 #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
197 #[cfg(feature = "internals")]
198 #[inline]
199 #[must_use]
200 #[allow(deprecated)]
201 pub fn store_data(&self) -> NativeCallContextStore {
202 NativeCallContextStore {
203 fn_name: self.fn_name.to_string(),
204 source: self.source.map(ToString::to_string),
205 global: self.global.clone(),
206 pos: self.pos,
207 }
208 }
209
210 #[inline(always)]
212 #[must_use]
213 pub const fn engine(&self) -> &Engine {
214 self.engine
215 }
216 #[inline(always)]
218 #[must_use]
219 pub const fn fn_name(&self) -> &str {
220 self.fn_name
221 }
222 #[inline(always)]
224 #[must_use]
225 pub const fn position(&self) -> Position {
226 self.pos
227 }
228 #[inline(always)]
230 #[must_use]
231 pub const fn call_level(&self) -> usize {
232 self.global.level
233 }
234 #[inline(always)]
236 #[must_use]
237 pub const fn source(&self) -> Option<&str> {
238 self.source
239 }
240 #[inline(always)]
242 #[must_use]
243 pub const fn tag(&self) -> Option<&Dynamic> {
244 Some(&self.global.tag)
245 }
246 #[cfg(not(feature = "no_module"))]
251 #[inline]
252 pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
253 self.global.iter_imports()
254 }
255 #[cfg(feature = "internals")]
260 #[inline(always)]
261 #[must_use]
262 pub const fn global_runtime_state(&self) -> &GlobalRuntimeState {
263 self.global
264 }
265 #[cfg(not(feature = "internals"))]
267 #[inline(always)]
268 #[must_use]
269 #[allow(dead_code)]
270 pub(crate) const fn global_runtime_state(&self) -> &GlobalRuntimeState {
271 self.global
272 }
273 #[cfg(not(feature = "no_function"))]
278 #[inline]
279 pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
280 self.global.lib.iter().map(<_>::as_ref)
281 }
282 #[cfg(not(feature = "no_function"))]
287 #[cfg(feature = "internals")]
288 #[inline(always)]
289 #[must_use]
290 pub fn namespaces(&self) -> &[crate::SharedModule] {
291 &self.global.lib
292 }
293 #[inline]
295 pub fn call_fn<T: Variant + Clone>(
296 &self,
297 fn_name: impl AsRef<str>,
298 args: impl FuncArgs,
299 ) -> RhaiResultOf<T> {
300 let mut arg_values = StaticVec::new_const();
301 args.parse(&mut arg_values);
302
303 let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
304
305 self._call_fn_raw(fn_name, args, false, false, false)
306 .and_then(|result| {
307 result.try_cast_raw().map_err(|r| {
308 let result_type = self.engine().map_type_name(r.type_name());
309 let cast_type = match type_name::<T>() {
310 typ if typ.contains("::") => self.engine.map_type_name(typ),
311 typ => typ,
312 };
313 ERR::ErrorMismatchOutputType(
314 cast_type.into(),
315 result_type.into(),
316 Position::NONE,
317 )
318 .into()
319 })
320 })
321 }
322 #[inline]
328 pub fn call_native_fn<T: Variant + Clone>(
329 &self,
330 fn_name: impl AsRef<str>,
331 args: impl FuncArgs,
332 ) -> RhaiResultOf<T> {
333 let mut arg_values = StaticVec::new_const();
334 args.parse(&mut arg_values);
335
336 let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
337
338 self._call_fn_raw(fn_name, args, true, false, false)
339 .and_then(|result| {
340 result.try_cast_raw().map_err(|r| {
341 let result_type = self.engine().map_type_name(r.type_name());
342 let cast_type = match type_name::<T>() {
343 typ if typ.contains("::") => self.engine.map_type_name(typ),
344 typ => typ,
345 };
346 ERR::ErrorMismatchOutputType(
347 cast_type.into(),
348 result_type.into(),
349 Position::NONE,
350 )
351 .into()
352 })
353 })
354 }
355 #[inline(always)]
375 pub fn call_fn_raw(
376 &self,
377 fn_name: impl AsRef<str>,
378 is_ref_mut: bool,
379 is_method_call: bool,
380 args: &mut [&mut Dynamic],
381 ) -> RhaiResult {
382 let name = fn_name.as_ref();
383 let native_only = !is_valid_function_name(name);
384 #[cfg(not(feature = "no_function"))]
385 let native_only = native_only && !crate::parser::is_anonymous_fn(name);
386
387 self._call_fn_raw(fn_name, args, native_only, is_ref_mut, is_method_call)
388 }
389 #[inline(always)]
410 pub fn call_native_fn_raw(
411 &self,
412 fn_name: impl AsRef<str>,
413 is_ref_mut: bool,
414 args: &mut [&mut Dynamic],
415 ) -> RhaiResult {
416 self._call_fn_raw(fn_name, args, true, is_ref_mut, false)
417 }
418
419 fn _call_fn_raw(
421 &self,
422 fn_name: impl AsRef<str>,
423 args: &mut [&mut Dynamic],
424 native_only: bool,
425 is_ref_mut: bool,
426 is_method_call: bool,
427 ) -> RhaiResult {
428 let global = &mut self.global.clone();
429 global.level += 1;
430
431 let caches = &mut Caches::new();
432
433 let fn_name = fn_name.as_ref();
434 let op_token = Token::lookup_symbol_from_syntax(fn_name);
435 let args_len = args.len();
436
437 if native_only {
438 return self
439 .engine()
440 .exec_native_fn_call(
441 global,
442 caches,
443 fn_name,
444 op_token.as_ref(),
445 calc_fn_hash(None, fn_name, args_len),
446 args,
447 is_ref_mut,
448 false,
449 Position::NONE,
450 )
451 .map(|(r, ..)| r);
452 }
453
454 let hash = match is_method_call {
457 #[cfg(not(feature = "no_function"))]
458 true => FnCallHashes::from_script_and_native(
459 calc_fn_hash(None, fn_name, args_len - 1),
460 calc_fn_hash(None, fn_name, args_len),
461 ),
462 #[cfg(feature = "no_function")]
463 true => FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args_len)),
464 _ => FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args_len)),
465 };
466
467 self.engine()
468 .exec_fn_call(
469 global,
470 caches,
471 None,
472 fn_name,
473 op_token.as_ref(),
474 hash,
475 args,
476 is_ref_mut,
477 is_method_call,
478 Position::NONE,
479 )
480 .map(|(r, ..)| r)
481 }
482}
483
484#[inline(always)]
487#[must_use]
488#[allow(dead_code)]
489pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
490 Shared::make_mut(value)
491}
492
493#[inline(always)]
495#[must_use]
496#[allow(dead_code)]
497pub fn shared_get_mut<T: Clone>(value: &mut Shared<T>) -> Option<&mut T> {
498 Shared::get_mut(value)
499}
500
501#[inline]
503#[must_use]
504#[allow(dead_code)]
505pub fn shared_take_or_clone<T: Clone>(value: Shared<T>) -> T {
506 shared_try_take(value).unwrap_or_else(|v| v.as_ref().clone())
507}
508
509#[inline(always)]
511#[allow(dead_code)]
512pub fn shared_try_take<T>(value: Shared<T>) -> Result<T, Shared<T>> {
513 Shared::try_unwrap(value)
514}
515
516#[inline]
522#[must_use]
523#[allow(dead_code)]
524pub fn shared_take<T>(value: Shared<T>) -> T {
525 shared_try_take(value)
526 .ok()
527 .unwrap_or_else(|| panic!("`value` is shared (i.e. has outstanding references)"))
528}
529
530#[inline(always)]
533#[must_use]
534#[allow(dead_code)]
535pub fn locked_read<T>(value: &Locked<T>) -> LockGuard<T> {
536 #[cfg(not(feature = "sync"))]
537 return value.borrow();
538
539 #[cfg(feature = "sync")]
540 return value.read().unwrap();
541}
542
543#[inline(always)]
546#[must_use]
547#[allow(dead_code)]
548pub fn locked_write<T>(value: &Locked<T>) -> LockGuardMut<T> {
549 #[cfg(not(feature = "sync"))]
550 return value.borrow_mut();
551
552 #[cfg(feature = "sync")]
553 return value.write().unwrap();
554}
555
556#[cfg(not(feature = "sync"))]
558pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult;
559#[cfg(feature = "sync")]
561pub type FnAny = dyn Fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult + Send + Sync;
562
563pub type FnBuiltin = (
565 fn(Option<NativeCallContext>, &mut FnCallArgs) -> RhaiResult,
566 bool,
567);
568
569#[cfg(not(feature = "sync"))]
571pub type FnIterator = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>>;
572#[cfg(feature = "sync")]
574pub type FnIterator =
575 dyn Fn(Dynamic) -> Box<dyn Iterator<Item = RhaiResultOf<Dynamic>>> + Send + Sync;
576
577#[cfg(not(feature = "sync"))]
579pub type FnPlugin = dyn PluginFunc;
580#[cfg(feature = "sync")]
582pub type FnPlugin = dyn PluginFunc + Send + Sync;
583
584#[cfg(not(feature = "unchecked"))]
586#[cfg(not(feature = "sync"))]
587pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic>;
588#[cfg(not(feature = "unchecked"))]
590#[cfg(feature = "sync")]
591pub type OnProgressCallback = dyn Fn(u64) -> Option<Dynamic> + Send + Sync;
592
593#[cfg(not(feature = "sync"))]
595pub type OnPrintCallback = dyn Fn(&str);
596#[cfg(feature = "sync")]
598pub type OnPrintCallback = dyn Fn(&str) + Send + Sync;
599
600#[cfg(not(feature = "sync"))]
602pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position);
603#[cfg(feature = "sync")]
605pub type OnDebugCallback = dyn Fn(&str, Option<&str>, Position) + Send + Sync;
606
607#[cfg(not(feature = "sync"))]
609pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token;
610#[cfg(feature = "sync")]
612pub type OnParseTokenCallback = dyn Fn(Token, Position, &TokenizeState) -> Token + Send + Sync;
613
614#[cfg(not(feature = "sync"))]
616pub type OnVarCallback = dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>>;
617#[cfg(feature = "sync")]
619pub type OnVarCallback =
620 dyn Fn(&str, usize, EvalContext) -> RhaiResultOf<Option<Dynamic>> + Send + Sync;
621
622#[cfg(not(feature = "sync"))]
624pub type OnDefVarCallback = dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool>;
625#[cfg(feature = "sync")]
627pub type OnDefVarCallback =
628 dyn Fn(bool, VarDefInfo, EvalContext) -> RhaiResultOf<bool> + Send + Sync;