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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use crate::{
    Engine, Identifier, Module, ModuleResolver, Position, RhaiResultOf, SharedModule, SmartString,
    ERR,
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
    collections::btree_map::{IntoIter, Iter},
    collections::BTreeMap,
    ops::AddAssign,
};

/// A static [module][Module] resolution service that serves [modules][Module] added into it.
///
/// # Example
///
/// ```
/// use rhai::{Engine, Module};
/// use rhai::module_resolvers::StaticModuleResolver;
///
/// let mut resolver = StaticModuleResolver::new();
///
/// let module = Module::new();
/// resolver.insert("hello", module);
///
/// let mut engine = Engine::new();
///
/// engine.set_module_resolver(resolver);
/// ```
#[derive(Debug, Clone, Default)]
pub struct StaticModuleResolver(BTreeMap<Identifier, SharedModule>);

impl StaticModuleResolver {
    /// Create a new [`StaticModuleResolver`].
    ///
    /// # Example
    ///
    /// ```
    /// use rhai::{Engine, Module};
    /// use rhai::module_resolvers::StaticModuleResolver;
    ///
    /// let mut resolver = StaticModuleResolver::new();
    ///
    /// let module = Module::new();
    /// resolver.insert("hello", module);
    ///
    /// let mut engine = Engine::new();
    /// engine.set_module_resolver(resolver);
    /// ```
    #[inline(always)]
    #[must_use]
    pub const fn new() -> Self {
        Self(BTreeMap::new())
    }
    /// Add a [module][Module] keyed by its path.
    #[inline]
    pub fn insert(&mut self, path: impl Into<Identifier>, mut module: Module) {
        let path = path.into();

        if module.id().is_none() {
            module.set_id(path.clone());
        }

        module.build_index();
        self.0.insert(path, module.into());
    }
    /// Remove a [module][Module] given its path.
    #[inline(always)]
    pub fn remove(&mut self, path: &str) -> Option<SharedModule> {
        self.0.remove(path)
    }
    /// Does the path exist?
    #[inline(always)]
    #[must_use]
    pub fn contains_path(&self, path: &str) -> bool {
        self.0.contains_key(path)
    }
    /// Get an iterator of all the [modules][Module].
    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = (&str, &SharedModule)> {
        self.0.iter().map(|(k, v)| (k.as_str(), v))
    }
    /// Get a mutable iterator of all the [modules][Module].
    #[inline]
    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut SharedModule)> {
        self.0.iter_mut().map(|(k, v)| (k.as_str(), v))
    }
    /// Get an iterator of all the [module][Module] paths.
    #[inline]
    pub fn paths(&self) -> impl Iterator<Item = &str> {
        self.0.keys().map(SmartString::as_str)
    }
    /// Get an iterator of all the [modules][Module].
    #[inline(always)]
    pub fn values(&self) -> impl Iterator<Item = &SharedModule> {
        self.0.values()
    }
    /// Remove all [modules][Module].
    #[inline(always)]
    pub fn clear(&mut self) -> &mut Self {
        self.0.clear();
        self
    }
    /// Returns `true` if this [`StaticModuleResolver`] contains no module resolvers.
    #[inline(always)]
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
    /// Get the number of [modules][Module] in this [`StaticModuleResolver`].
    #[inline(always)]
    #[must_use]
    pub fn len(&self) -> usize {
        self.0.len()
    }
    /// Merge another [`StaticModuleResolver`] into this.
    /// The other [`StaticModuleResolver`] is consumed.
    ///
    /// Existing modules of the same path name are overwritten.
    #[inline]
    pub fn merge(&mut self, other: Self) -> &mut Self {
        self.0.extend(other.0.into_iter());
        self
    }
}

impl IntoIterator for StaticModuleResolver {
    type Item = (Identifier, SharedModule);
    type IntoIter = IntoIter<SmartString, SharedModule>;

    #[inline(always)]
    #[must_use]
    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<'a> IntoIterator for &'a StaticModuleResolver {
    type Item = (&'a Identifier, &'a SharedModule);
    type IntoIter = Iter<'a, SmartString, SharedModule>;

    #[inline(always)]
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl AddAssign<Self> for StaticModuleResolver {
    #[inline(always)]
    fn add_assign(&mut self, rhs: Self) {
        self.merge(rhs);
    }
}

impl ModuleResolver for StaticModuleResolver {
    #[inline]
    fn resolve(
        &self,
        _: &Engine,
        _: Option<&str>,
        path: &str,
        pos: Position,
    ) -> RhaiResultOf<SharedModule> {
        self.0
            .get(path)
            .cloned()
            .ok_or_else(|| ERR::ErrorModuleNotFound(path.into(), pos).into())
    }
}