rhai/api/register.rs
1//! Module that defines the public function/module registration API of [`Engine`].
2
3use crate::func::{FnCallArgs, RhaiFunc, RhaiNativeFunc, SendSync};
4use crate::module::FuncRegistration;
5use crate::types::dynamic::Variant;
6use crate::{
7 Dynamic, Engine, Identifier, Module, NativeCallContext, RhaiResultOf, Shared, SharedModule,
8};
9use std::any::{type_name, TypeId};
10#[cfg(feature = "no_std")]
11use std::prelude::v1::*;
12
13#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
14use crate::func::register::Mut;
15
16impl Engine {
17 /// Get a mutable reference to the global namespace module
18 /// (which is the first module in `global_modules`).
19 #[inline(always)]
20 #[must_use]
21 pub(crate) fn global_namespace_mut(&mut self) -> &mut Module {
22 if self.global_modules.is_empty() {
23 let mut global_namespace = Module::new();
24 global_namespace.set_internal(true);
25 self.global_modules.push(global_namespace.into());
26 }
27
28 Shared::get_mut(self.global_modules.first_mut().unwrap()).unwrap()
29 }
30 /// Register a custom function with the [`Engine`].
31 ///
32 /// # Assumptions
33 ///
34 /// * **Accessibility**: The function namespace is [`FnNamespace::Global`][`crate::FnNamespace::Global`].
35 ///
36 /// * **Purity**: The function is assumed to be _pure_ unless it is a property setter or an index setter.
37 ///
38 /// * **Volatility**: The function is assumed to be _non-volatile_ -- i.e. it guarantees the same result for the same input(s).
39 ///
40 /// # Example
41 ///
42 /// ```
43 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
44 /// use rhai::Engine;
45 ///
46 /// // Normal function
47 /// fn add(x: i64, y: i64) -> i64 {
48 /// x + y
49 /// }
50 ///
51 /// let mut engine = Engine::new();
52 ///
53 /// engine.register_fn("add", add);
54 ///
55 /// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
56 ///
57 /// // You can also register a closure.
58 /// engine.register_fn("sub", |x: i64, y: i64| x - y );
59 ///
60 /// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
61 /// # Ok(())
62 /// # }
63 /// ```
64 #[inline]
65 pub fn register_fn<
66 A: 'static,
67 const N: usize,
68 const X: bool,
69 R: Variant + Clone,
70 const F: bool,
71 >(
72 &mut self,
73 name: impl AsRef<str> + Into<Identifier>,
74 func: impl RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
75 ) -> &mut Self {
76 FuncRegistration::new(name.into()).register_into_engine(self, func);
77
78 self
79 }
80 /// Register a function of the [`Engine`].
81 ///
82 /// # WARNING - Low Level API
83 ///
84 /// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s
85 /// indicating the actual types of the parameters.
86 ///
87 /// # Arguments
88 ///
89 /// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic].
90 /// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
91 ///
92 /// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
93 ///
94 /// To access an argument value and avoid cloning, use `args[n].take().cast::<T>()`.
95 /// Notice that this will _consume_ the argument, replacing it with `()`.
96 ///
97 /// To access the first mutable parameter, use `args.get_mut(0).unwrap()`
98 #[inline(always)]
99 pub fn register_raw_fn<T: Variant + Clone>(
100 &mut self,
101 name: impl AsRef<str> + Into<Identifier>,
102 arg_types: impl AsRef<[TypeId]>,
103 func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf<T> + SendSync + 'static,
104 ) -> &mut Self {
105 let name = name.into();
106 let arg_types = arg_types.as_ref();
107 let is_pure = true;
108
109 #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
110 let is_pure = is_pure && (arg_types.len() != 3 || name != crate::engine::FN_IDX_SET);
111 #[cfg(not(feature = "no_object"))]
112 let is_pure = is_pure && (arg_types.len() != 2 || !name.starts_with(crate::engine::FN_SET));
113
114 FuncRegistration::new(name)
115 .in_global_namespace()
116 .set_into_module_raw(
117 self.global_namespace_mut(),
118 arg_types,
119 RhaiFunc::Method {
120 func: Shared::new(
121 move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
122 func(ctx.unwrap(), args).map(Dynamic::from)
123 },
124 ),
125 has_context: true,
126 is_pure,
127 is_volatile: true,
128 },
129 );
130
131 self
132 }
133 /// Register a custom type for use with the [`Engine`].
134 /// The type must implement [`Clone`].
135 ///
136 /// # Example
137 ///
138 /// ```
139 /// #[derive(Debug, Clone, Eq, PartialEq)]
140 /// struct TestStruct {
141 /// field: i64
142 /// }
143 ///
144 /// impl TestStruct {
145 /// fn new() -> Self {
146 /// Self { field: 1 }
147 /// }
148 /// fn update(&mut self, offset: i64) {
149 /// self.field += offset;
150 /// }
151 /// }
152 ///
153 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
154 /// use rhai::Engine;
155 ///
156 /// let mut engine = Engine::new();
157 ///
158 /// // Register API for the custom type.
159 /// engine
160 /// .register_type::<TestStruct>()
161 /// .register_fn("new_ts", TestStruct::new)
162 /// // Use `register_fn` to register methods on the type.
163 /// .register_fn("update", TestStruct::update);
164 ///
165 /// # #[cfg(not(feature = "no_object"))]
166 /// assert_eq!(
167 /// engine.eval::<TestStruct>("let x = new_ts(); x.update(41); x")?,
168 /// TestStruct { field: 42 }
169 /// );
170 /// # Ok(())
171 /// # }
172 /// ```
173 #[inline(always)]
174 pub fn register_type<T: Variant + Clone>(&mut self) -> &mut Self {
175 self.register_type_with_name::<T>(type_name::<T>())
176 }
177 /// Register a custom type for use with the [`Engine`], with a pretty-print name
178 /// for the `type_of` function. The type must implement [`Clone`].
179 ///
180 /// # Example
181 ///
182 /// ```
183 /// #[derive(Clone)]
184 /// struct TestStruct {
185 /// field: i64
186 /// }
187 ///
188 /// impl TestStruct {
189 /// fn new() -> Self {
190 /// Self { field: 1 }
191 /// }
192 /// }
193 ///
194 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
195 /// use rhai::Engine;
196 ///
197 /// let mut engine = Engine::new();
198 ///
199 /// // Register API for the custom type.
200 /// engine
201 /// .register_type::<TestStruct>()
202 /// .register_fn("new_ts", TestStruct::new);
203 ///
204 /// assert_eq!(
205 /// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
206 /// "rust_out::TestStruct"
207 /// );
208 ///
209 /// // Re-register the custom type with a name.
210 /// engine.register_type_with_name::<TestStruct>("Hello");
211 ///
212 /// assert_eq!(
213 /// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
214 /// "Hello"
215 /// );
216 /// # Ok(())
217 /// # }
218 /// ```
219 #[inline(always)]
220 pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
221 self.global_namespace_mut().set_custom_type::<T>(name);
222 self
223 }
224 /// Register a custom type for use with the [`Engine`], with a pretty-print name
225 /// for the `type_of` function. The type must implement [`Clone`].
226 ///
227 /// # WARNING - Low Level API
228 ///
229 /// This function is low level.
230 #[inline(always)]
231 pub fn register_type_with_name_raw(
232 &mut self,
233 type_path: impl Into<Identifier>,
234 name: impl Into<Identifier>,
235 ) -> &mut Self {
236 // Add the pretty-print type name into the map
237 self.global_namespace_mut()
238 .set_custom_type_raw(type_path, name);
239 self
240 }
241 /// Register a type iterator for an iterable type with the [`Engine`].
242 /// This is an advanced API.
243 #[inline(always)]
244 pub fn register_iterator<T>(&mut self) -> &mut Self
245 where
246 T: Variant + Clone + IntoIterator,
247 <T as IntoIterator>::Item: Variant + Clone,
248 {
249 self.global_namespace_mut().set_iterable::<T>();
250 self
251 }
252 /// Register a fallible type iterator for an iterable type with the [`Engine`].
253 /// This is an advanced API.
254 #[inline(always)]
255 pub fn register_iterator_result<T, R>(&mut self) -> &mut Self
256 where
257 T: Variant + Clone + IntoIterator<Item = RhaiResultOf<R>>,
258 R: Variant + Clone,
259 {
260 self.global_namespace_mut().set_iterable_result::<T, R>();
261 self
262 }
263 /// Register a getter function for a member of a registered type with the [`Engine`].
264 ///
265 /// The function signature must start with `&mut self` and not `&self`.
266 ///
267 /// Not available under `no_object`.
268 ///
269 /// # Example
270 ///
271 /// ```
272 /// #[derive(Clone)]
273 /// struct TestStruct {
274 /// field: i64
275 /// }
276 ///
277 /// impl TestStruct {
278 /// fn new() -> Self {
279 /// Self { field: 1 }
280 /// }
281 /// // Even a getter must start with `&mut self` and not `&self`.
282 /// fn get_field(&mut self) -> i64 {
283 /// self.field
284 /// }
285 /// }
286 ///
287 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
288 /// use rhai::Engine;
289 ///
290 /// let mut engine = Engine::new();
291 ///
292 /// // Register API for the custom type.
293 /// engine
294 /// .register_type::<TestStruct>()
295 /// .register_fn("new_ts", TestStruct::new)
296 /// // Register a getter on a property (notice it doesn't have to be the same name).
297 /// .register_get("xyz", TestStruct::get_field);
298 ///
299 /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
300 /// # Ok(())
301 /// # }
302 /// ```
303 #[cfg(not(feature = "no_object"))]
304 #[inline(always)]
305 pub fn register_get<T: Variant + Clone, const X: bool, R: Variant + Clone, const F: bool>(
306 &mut self,
307 name: impl AsRef<str>,
308 get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, F> + SendSync + 'static,
309 ) -> &mut Self {
310 self.register_fn(crate::engine::make_getter(name.as_ref()), get_fn)
311 }
312
313 /// Register a setter function for a member of a registered type with the [`Engine`].
314 ///
315 /// Not available under `no_object`.
316 ///
317 /// # Example
318 ///
319 /// ```
320 /// #[derive(Debug, Clone, Eq, PartialEq)]
321 /// struct TestStruct {
322 /// field: i64
323 /// }
324 ///
325 /// impl TestStruct {
326 /// fn new() -> Self {
327 /// Self { field: 1 }
328 /// }
329 /// fn set_field(&mut self, new_val: i64) {
330 /// self.field = new_val;
331 /// }
332 /// }
333 ///
334 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
335 /// use rhai::Engine;
336 ///
337 /// let mut engine = Engine::new();
338 ///
339 /// // Register API for the custom type.
340 /// engine
341 /// .register_type::<TestStruct>()
342 /// .register_fn("new_ts", TestStruct::new)
343 /// // Register a setter on a property (notice it doesn't have to be the same name)
344 /// .register_set("xyz", TestStruct::set_field);
345 ///
346 /// // Notice that, with a getter, there is no way to get the property value
347 /// assert_eq!(
348 /// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
349 /// TestStruct { field: 42 }
350 /// );
351 /// # Ok(())
352 /// # }
353 /// ```
354 #[cfg(not(feature = "no_object"))]
355 #[inline(always)]
356 pub fn register_set<T: Variant + Clone, const X: bool, R: Variant + Clone, const F: bool>(
357 &mut self,
358 name: impl AsRef<str>,
359 set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X, (), F> + SendSync + 'static,
360 ) -> &mut Self {
361 self.register_fn(crate::engine::make_setter(name.as_ref()), set_fn)
362 }
363 /// Short-hand for registering both getter and setter functions
364 /// of a registered type with the [`Engine`].
365 ///
366 /// All function signatures must start with `&mut self` and not `&self`.
367 ///
368 /// Not available under `no_object`.
369 ///
370 /// # Example
371 ///
372 /// ```
373 /// #[derive(Clone)]
374 /// struct TestStruct {
375 /// field: i64
376 /// }
377 ///
378 /// impl TestStruct {
379 /// fn new() -> Self {
380 /// Self { field: 1 }
381 /// }
382 /// // Even a getter must start with `&mut self` and not `&self`.
383 /// fn get_field(&mut self) -> i64 {
384 /// self.field
385 /// }
386 /// fn set_field(&mut self, new_val: i64) {
387 /// self.field = new_val;
388 /// }
389 /// }
390 ///
391 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
392 /// use rhai::Engine;
393 ///
394 /// let mut engine = Engine::new();
395 ///
396 /// // Register API for the custom type.
397 /// engine
398 /// .register_type::<TestStruct>()
399 /// .register_fn("new_ts", TestStruct::new)
400 /// // Register both a getter and a setter on a property
401 /// // (notice it doesn't have to be the same name)
402 /// .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
403 ///
404 /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
405 /// # Ok(())
406 /// # }
407 /// ```
408 #[cfg(not(feature = "no_object"))]
409 #[inline(always)]
410 pub fn register_get_set<
411 T: Variant + Clone,
412 const X1: bool,
413 const X2: bool,
414 R: Variant + Clone,
415 const F1: bool,
416 const F2: bool,
417 >(
418 &mut self,
419 name: impl AsRef<str>,
420 get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X1, R, F1> + SendSync + 'static,
421 set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X2, (), F2> + SendSync + 'static,
422 ) -> &mut Self {
423 self.register_get(&name, get_fn).register_set(&name, set_fn)
424 }
425 /// Register an index getter for a custom type with the [`Engine`].
426 ///
427 /// The function signature must start with `&mut self` and not `&self`.
428 ///
429 /// Not available under both `no_index` and `no_object`.
430 ///
431 /// # Panics
432 ///
433 /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
434 /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
435 /// Indexers for arrays, object maps, strings and integers cannot be registered.
436 ///
437 /// # Example
438 ///
439 /// ```
440 /// #[derive(Clone)]
441 /// struct TestStruct {
442 /// fields: Vec<i64>
443 /// }
444 ///
445 /// impl TestStruct {
446 /// fn new() -> Self {
447 /// Self { fields: vec![1, 2, 3, 4, 5] }
448 /// }
449 /// // Even a getter must start with `&mut self` and not `&self`.
450 /// fn get_field(&mut self, index: i64) -> i64 {
451 /// self.fields[index as usize]
452 /// }
453 /// }
454 ///
455 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
456 /// use rhai::Engine;
457 ///
458 /// let mut engine = Engine::new();
459 ///
460 /// // Register API for the custom type.
461 /// # #[cfg(not(feature = "no_object"))]
462 /// engine.register_type::<TestStruct>();
463 ///
464 /// engine
465 /// .register_fn("new_ts", TestStruct::new)
466 /// // Register an indexer.
467 /// .register_indexer_get(TestStruct::get_field);
468 ///
469 /// # #[cfg(not(feature = "no_index"))]
470 /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
471 /// # Ok(())
472 /// # }
473 /// ```
474 #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
475 #[inline(always)]
476 pub fn register_indexer_get<
477 T: Variant + Clone,
478 IDX: Variant + Clone,
479 const X: bool,
480 R: Variant + Clone,
481 const F: bool,
482 >(
483 &mut self,
484 get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X, R, F> + SendSync + 'static,
485 ) -> &mut Self {
486 self.register_fn(crate::engine::FN_IDX_GET, get_fn)
487 }
488 /// Register an index setter for a custom type with the [`Engine`].
489 ///
490 /// Not available under both `no_index` and `no_object`.
491 ///
492 /// # Panics
493 ///
494 /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
495 /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
496 /// Indexers for arrays, object maps, strings and integers cannot be registered.
497 ///
498 /// # Example
499 ///
500 /// ```
501 /// #[derive(Clone)]
502 /// struct TestStruct {
503 /// fields: Vec<i64>
504 /// }
505 ///
506 /// impl TestStruct {
507 /// fn new() -> Self {
508 /// Self { fields: vec![1, 2, 3, 4, 5] }
509 /// }
510 /// fn set_field(&mut self, index: i64, value: i64) {
511 /// self.fields[index as usize] = value;
512 /// }
513 /// }
514 ///
515 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
516 /// use rhai::Engine;
517 ///
518 /// let mut engine = Engine::new();
519 ///
520 /// // Register API for the custom type.
521 /// # #[cfg(not(feature = "no_object"))]
522 /// engine.register_type::<TestStruct>();
523 ///
524 /// engine
525 /// .register_fn("new_ts", TestStruct::new)
526 /// // Register an indexer.
527 /// .register_indexer_set(TestStruct::set_field);
528 ///
529 /// # #[cfg(not(feature = "no_index"))]
530 /// let result = engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?;
531 ///
532 /// # #[cfg(not(feature = "no_index"))]
533 /// assert_eq!(result.fields[2], 42);
534 /// # Ok(())
535 /// # }
536 /// ```
537 #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
538 #[inline(always)]
539 pub fn register_indexer_set<
540 T: Variant + Clone,
541 IDX: Variant + Clone,
542 const X: bool,
543 R: Variant + Clone,
544 const F: bool,
545 >(
546 &mut self,
547 set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X, (), F> + SendSync + 'static,
548 ) -> &mut Self {
549 self.register_fn(crate::engine::FN_IDX_SET, set_fn)
550 }
551 /// Short-hand for registering both index getter and setter functions for a custom type with the [`Engine`].
552 ///
553 /// Not available under both `no_index` and `no_object`.
554 ///
555 /// # Panics
556 ///
557 /// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
558 /// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
559 /// Indexers for arrays, object maps, strings and integers cannot be registered.
560 ///
561 /// # Example
562 ///
563 /// ```
564 /// #[derive(Clone)]
565 /// struct TestStruct {
566 /// fields: Vec<i64>
567 /// }
568 ///
569 /// impl TestStruct {
570 /// fn new() -> Self {
571 /// Self { fields: vec![1, 2, 3, 4, 5] }
572 /// }
573 /// // Even a getter must start with `&mut self` and not `&self`.
574 /// fn get_field(&mut self, index: i64) -> i64 {
575 /// self.fields[index as usize]
576 /// }
577 /// fn set_field(&mut self, index: i64, value: i64) {
578 /// self.fields[index as usize] = value;
579 /// }
580 /// }
581 ///
582 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
583 /// use rhai::Engine;
584 ///
585 /// let mut engine = Engine::new();
586 ///
587 /// // Register API for the custom type.
588 /// # #[cfg(not(feature = "no_object"))]
589 /// engine.register_type::<TestStruct>();
590 ///
591 /// engine
592 /// .register_fn("new_ts", TestStruct::new)
593 /// // Register an indexer.
594 /// .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
595 ///
596 /// # #[cfg(not(feature = "no_index"))]
597 /// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2] = 42; a[2]")?, 42);
598 /// # Ok(())
599 /// # }
600 /// ```
601 #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
602 #[inline(always)]
603 pub fn register_indexer_get_set<
604 T: Variant + Clone,
605 IDX: Variant + Clone,
606 const X1: bool,
607 const X2: bool,
608 R: Variant + Clone,
609 const F1: bool,
610 const F2: bool,
611 >(
612 &mut self,
613 get_fn: impl RhaiNativeFunc<(Mut<T>, IDX), 2, X1, R, F1> + SendSync + 'static,
614 set_fn: impl RhaiNativeFunc<(Mut<T>, IDX, R), 3, X2, (), F2> + SendSync + 'static,
615 ) -> &mut Self {
616 self.register_indexer_get(get_fn)
617 .register_indexer_set(set_fn)
618 }
619 /// Register a shared [`Module`] into the global namespace of [`Engine`].
620 ///
621 /// All functions and type iterators are automatically available to scripts without namespace
622 /// qualifications.
623 ///
624 /// Sub-modules and variables are **ignored**.
625 ///
626 /// When searching for functions, modules loaded later are preferred. In other words, loaded
627 /// modules are searched in reverse order.
628 #[inline(always)]
629 pub fn register_global_module(&mut self, module: SharedModule) -> &mut Self {
630 // Make sure the global namespace is created.
631 let _ = self.global_namespace_mut();
632
633 // Insert the module into the front.
634 // The first module is always the global namespace.
635 self.global_modules.insert(1, module);
636 self
637 }
638 /// Register a shared [`Module`] as a static module namespace with the [`Engine`].
639 ///
640 /// Functions marked [`FnNamespace::Global`][`crate::FnNamespace::Global`] and type iterators are exposed to scripts without
641 /// namespace qualifications.
642 ///
643 /// Not available under `no_module`.
644 ///
645 /// # Example
646 ///
647 /// ```
648 /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
649 /// use rhai::{Engine, Shared, Module};
650 ///
651 /// let mut engine = Engine::new();
652 ///
653 /// // Create the module
654 /// let mut module = Module::new();
655 /// module.set_native_fn("calc", |x: i64| Ok(x + 1));
656 ///
657 /// let module: Shared<Module> = module.into();
658 ///
659 /// engine
660 /// // Register the module as a fixed sub-module
661 /// .register_static_module("foo::bar::baz", module.clone())
662 /// // Multiple registrations to the same partial path is also OK!
663 /// .register_static_module("foo::bar::hello", module.clone())
664 /// .register_static_module("CalcService", module);
665 ///
666 /// assert_eq!(engine.eval::<i64>("foo::bar::baz::calc(41)")?, 42);
667 /// assert_eq!(engine.eval::<i64>("foo::bar::hello::calc(41)")?, 42);
668 /// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
669 /// # Ok(())
670 /// # }
671 /// ```
672 #[cfg(not(feature = "no_module"))]
673 pub fn register_static_module(
674 &mut self,
675 name: impl AsRef<str>,
676 module: SharedModule,
677 ) -> &mut Self {
678 use std::collections::BTreeMap;
679
680 fn register_static_module_raw(
681 root: &mut BTreeMap<Identifier, SharedModule>,
682 name: &str,
683 module: SharedModule,
684 ) {
685 let separator = crate::engine::NAMESPACE_SEPARATOR;
686
687 if let Some((top_namespace, remainder)) = name
688 .split_once(separator)
689 .map(|(a, b)| (a.trim(), b.trim()))
690 {
691 let mut m = if root.is_empty() || !root.contains_key(top_namespace) {
692 Module::new()
693 } else {
694 crate::func::shared_take_or_clone(root.remove(top_namespace).unwrap())
695 };
696 register_static_module_raw(m.get_sub_modules_mut(), remainder, module);
697 m.build_index();
698 if m.id().is_none() {
699 m.set_id(top_namespace);
700 }
701 root.insert(top_namespace.into(), m.into());
702 } else if module.is_indexed() {
703 let module = if module.id().is_none() {
704 // Make a clone copy if the module does not have an ID
705 let mut m = crate::func::shared_take_or_clone(module);
706 m.set_id(name);
707 m.into()
708 } else {
709 module
710 };
711 root.insert(name.into(), module);
712 } else {
713 // Index the module (making a clone copy if necessary) if it is not indexed
714 let mut module = crate::func::shared_take_or_clone(module);
715 module.build_index();
716 if module.id().is_none() {
717 module.set_id(name);
718 }
719 root.insert(name.into(), module.into());
720 }
721 }
722
723 register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
724 self
725 }
726 /// _(metadata)_ Generate a list of all registered functions.
727 /// Exported under the `metadata` feature only.
728 ///
729 /// Functions from the following sources are included, in order:
730 /// 1) Functions registered into the global namespace
731 /// 2) Functions in registered sub-modules
732 /// 3) Functions in registered packages
733 /// 4) Functions in standard packages (optional)
734 #[cfg(feature = "metadata")]
735 #[inline]
736 #[must_use]
737 pub fn gen_fn_signatures(&self, include_standard_packages: bool) -> Vec<String> {
738 let mut signatures = Vec::with_capacity(64);
739
740 if let Some(global_namespace) = self.global_modules.first() {
741 signatures.extend(
742 global_namespace.gen_fn_signatures_with_mapper(|s| self.format_param_type(s)),
743 );
744 }
745
746 #[cfg(not(feature = "no_module"))]
747 for (name, m) in &self.global_sub_modules {
748 signatures.extend(
749 m.gen_fn_signatures_with_mapper(|s| self.format_param_type(s))
750 .map(|f| format!("{name}::{f}")),
751 );
752 }
753
754 signatures.extend(
755 self.global_modules
756 .iter()
757 .skip(1)
758 .filter(|m| include_standard_packages || !m.is_standard_lib())
759 .flat_map(|m| m.gen_fn_signatures_with_mapper(|s| self.format_param_type(s))),
760 );
761
762 signatures
763 }
764
765 /// Collect the [`FuncInfo`][crate::module::FuncInfo] of all functions, native or script-defined,
766 /// mapping them into any type.
767 /// Exported under the `internals` feature only.
768 ///
769 /// Return [`None`] from the `mapper` to skip a function.
770 ///
771 /// Functions from the following sources are included, in order:
772 /// 1) Functions defined in the current script (if any)
773 /// 2) Functions registered into the global namespace
774 /// 3) Functions in registered packages
775 /// 4) Functions in standard packages (optional)
776 /// 5) Functions defined in modules `import`-ed by the current script (if any)
777 /// 6) Functions in registered sub-modules
778 #[cfg(feature = "internals")]
779 #[inline(always)]
780 pub fn collect_fn_metadata<T>(
781 &self,
782 ctx: Option<&NativeCallContext>,
783 mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
784 include_standard_packages: bool,
785 ) -> Vec<T> {
786 self.collect_fn_metadata_impl(ctx, mapper, include_standard_packages)
787 }
788
789 /// Collect the [`FuncInfo`][crate::module::FuncInfo] of all functions, native or script-defined,
790 /// mapping them into any type.
791 ///
792 /// Return [`None`] from the `mapper` to skip a function.
793 ///
794 /// Functions from the following sources are included, in order:
795 /// 1) Functions defined in the current script (if any)
796 /// 2) Functions registered into the global namespace
797 /// 3) Functions in registered packages
798 /// 4) Functions in standard packages (optional)
799 /// 5) Functions defined in modules `import`-ed by the current script (if any)
800 /// 6) Functions in registered sub-modules
801 #[allow(dead_code)]
802 pub(crate) fn collect_fn_metadata_impl<T>(
803 &self,
804 _ctx: Option<&NativeCallContext>,
805 mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
806 include_standard_packages: bool,
807 ) -> Vec<T> {
808 let mut list = Vec::new();
809
810 #[cfg(not(feature = "no_function"))]
811 if let Some(ctx) = _ctx {
812 ctx.iter_namespaces()
813 .flat_map(Module::iter_fn)
814 .filter_map(|(func, f)| {
815 mapper(crate::module::FuncInfo {
816 metadata: f,
817 #[cfg(not(feature = "no_module"))]
818 namespace: Identifier::new_const(),
819 script: func.get_script_fn_def().map(|f| (&**f).into()),
820 })
821 })
822 .for_each(|v| list.push(v));
823 }
824
825 self.global_modules
826 .iter()
827 .filter(|m| include_standard_packages || !m.is_standard_lib())
828 .flat_map(|m| m.iter_fn())
829 .filter_map(|(_func, f)| {
830 mapper(crate::module::FuncInfo {
831 metadata: f,
832 #[cfg(not(feature = "no_module"))]
833 namespace: Identifier::new_const(),
834 #[cfg(not(feature = "no_function"))]
835 script: _func.get_script_fn_def().map(|f| (&**f).into()),
836 })
837 })
838 .for_each(|v| list.push(v));
839
840 #[cfg(not(feature = "no_module"))]
841 {
842 // Recursively scan modules for script-defined functions.
843 fn scan_module_recursive<T>(
844 list: &mut Vec<T>,
845 namespace: &str,
846 module: &Module,
847 mapper: impl Fn(crate::module::FuncInfo) -> Option<T> + Copy,
848 ) {
849 use crate::engine::NAMESPACE_SEPARATOR;
850 use crate::SmartString;
851
852 module
853 .iter_fn()
854 .filter_map(|(_func, f)| {
855 mapper(crate::module::FuncInfo {
856 metadata: f,
857 namespace: namespace.into(),
858 #[cfg(not(feature = "no_function"))]
859 script: _func.get_script_fn_def().map(|f| (&**f).into()),
860 })
861 })
862 .for_each(|v| list.push(v));
863
864 module.iter_sub_modules().for_each(|(name, m)| {
865 use std::fmt::Write;
866 let mut ns = SmartString::new_const();
867 write!(&mut ns, "{namespace}{NAMESPACE_SEPARATOR}{name}").unwrap();
868 scan_module_recursive(list, &ns, m, mapper);
869 });
870 }
871
872 if let Some(ctx) = _ctx {
873 ctx.global_runtime_state()
874 .iter_imports_raw()
875 .for_each(|(ns, m)| scan_module_recursive(&mut list, ns, m, mapper));
876 }
877
878 self.global_sub_modules
879 .iter()
880 .for_each(|(name, m)| scan_module_recursive(&mut list, name, m, mapper));
881 }
882
883 list
884 }
885}