1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Module containing all built-in _packages_ available to Rhai, plus facilities to define custom packages.


use crate::fn_native::{CallableFunction, IteratorFn, Shared};
use crate::module::Module;
use crate::StaticVec;

use crate::stdlib::any::TypeId;

pub(crate) mod arithmetic;
mod array_basic;
mod eval;
mod fn_basic;
mod iter_basic;
mod logic;
mod map_basic;
mod math_basic;
mod pkg_core;
mod pkg_std;
mod string_basic;
mod string_more;
mod time_basic;

pub use arithmetic::ArithmeticPackage;
#[cfg(not(feature = "no_index"))]
pub use array_basic::BasicArrayPackage;
pub use eval::EvalPackage;
pub use fn_basic::BasicFnPackage;
pub use iter_basic::BasicIteratorPackage;
pub use logic::LogicPackage;
#[cfg(not(feature = "no_object"))]
pub use map_basic::BasicMapPackage;
pub use math_basic::BasicMathPackage;
pub use pkg_core::CorePackage;
pub use pkg_std::StandardPackage;
pub use string_basic::BasicStringPackage;
pub use string_more::MoreStringPackage;
#[cfg(not(feature = "no_std"))]
pub use time_basic::BasicTimePackage;

/// Trait that all packages must implement.

pub trait Package {
    /// Register all the functions in a package into a store.

    fn init(lib: &mut Module);

    /// Retrieve the generic package library from this package.

    fn get(&self) -> PackageLibrary;
}

/// A sharable `Module` to facilitate sharing library instances.

pub type PackageLibrary = Shared<Module>;

/// Type containing a collection of `PackageLibrary` instances.

/// All function and type iterator keys in the loaded packages are indexed for fast access.

#[derive(Debug, Clone, Default)]
pub(crate) struct PackagesCollection(StaticVec<PackageLibrary>);

impl PackagesCollection {
    /// Add a `PackageLibrary` into the `PackagesCollection`.

    pub fn push(&mut self, package: PackageLibrary) {
        // Later packages override previous ones.

        self.0.insert(0, package);
    }
    /// Does the specified function hash key exist in the `PackagesCollection`?

    #[allow(dead_code)]
    pub fn contains_fn(&self, hash: u64, public_only: bool) -> bool {
        self.0.iter().any(|p| p.contains_fn(hash, public_only))
    }
    /// Get specified function via its hash key.

    pub fn get_fn(&self, hash: u64, public_only: bool) -> Option<&CallableFunction> {
        self.0
            .iter()
            .map(|p| p.get_fn(hash, public_only))
            .find(|f| f.is_some())
            .flatten()
    }
    /// Does the specified TypeId iterator exist in the `PackagesCollection`?

    #[allow(dead_code)]
    pub fn contains_iter(&self, id: TypeId) -> bool {
        self.0.iter().any(|p| p.contains_iter(id))
    }
    /// Get the specified TypeId iterator.

    pub fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
        self.0
            .iter()
            .map(|p| p.get_iter(id))
            .find(|f| f.is_some())
            .flatten()
    }
}

/// Macro that makes it easy to define a _package_ (which is basically a shared module)

/// and register functions into it.

///

/// Functions can be added to the package using the standard module methods such as

/// `set_fn_2`, `set_fn_3_mut`, `set_fn_0` etc.

///

/// # Example

///

/// ```

/// use rhai::{Dynamic, EvalAltResult};

/// use rhai::def_package;

///

/// fn add(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> { Ok(x + y) }

///

/// def_package!(rhai:MyPackage:"My super-duper package", lib,

/// {

///     // Load a binary function with all value parameters.

///     lib.set_fn_2("my_add", add);

/// });

/// ```

///

/// The above defines a package named 'MyPackage' with a single function named 'my_add'.

#[macro_export]
macro_rules! def_package {
    ($root:ident : $package:ident : $comment:expr , $lib:ident , $block:stmt) => {
        #[doc=$comment]
        pub struct $package($root::packages::PackageLibrary);

        impl $root::packages::Package for $package {
            fn get(&self) -> $root::packages::PackageLibrary {
                self.0.clone()
            }

            fn init($lib: &mut $root::Module) {
                $block
            }
        }

        impl $package {
            pub fn new() -> Self {
                let mut module = $root::Module::new_with_capacity(512);
                <Self as $root::packages::Package>::init(&mut module);
                Self(module.into())
            }
        }
    };
}