Build Module type plus engine hooks.
This commit is contained in:
137
src/module.rs
137
src/module.rs
@@ -1,35 +1,134 @@
|
||||
//! Module defining external-loaded modules for Rhai.
|
||||
|
||||
use crate::any::Dynamic;
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::engine::{FnAny, FunctionsLib};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::token::Position;
|
||||
use crate::utils::StaticVec;
|
||||
|
||||
use crate::stdlib::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
string::String,
|
||||
};
|
||||
use crate::stdlib::{collections::HashMap, fmt, string::String};
|
||||
|
||||
/// An imported module.
|
||||
/// An imported module, which may contain variables, sub-modules,
|
||||
/// external Rust functions, and script-defined functions.
|
||||
///
|
||||
/// Not available under the `no_module` feature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Module(HashMap<String, Dynamic>);
|
||||
#[derive(Default)]
|
||||
pub struct Module {
|
||||
/// Sub-modules.
|
||||
modules: HashMap<String, Module>,
|
||||
/// Module variables, including sub-modules.
|
||||
variables: HashMap<String, Dynamic>,
|
||||
/// External Rust functions.
|
||||
functions: HashMap<u64, Box<FnAny>>,
|
||||
/// Script-defined functions.
|
||||
lib: FunctionsLib,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Module {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"<module {:?}, functions={}, lib={}>",
|
||||
self.variables,
|
||||
self.functions.len(),
|
||||
self.lib.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Module {
|
||||
fn clone(&self) -> Self {
|
||||
// `Module` implements `Clone` so it can fit inside a `Dynamic`
|
||||
// but we should never actually clone it.
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Create a new module.
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Module {
|
||||
type Target = HashMap<String, Dynamic>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
/// Does a variable exist in the module?
|
||||
pub fn contains_variable(&self, name: &str) -> bool {
|
||||
self.variables.contains_key(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Module {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
/// Get the value of a module variable.
|
||||
pub fn get_variable_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||
self.get_variable(name).and_then(|v| v.try_cast::<T>())
|
||||
}
|
||||
|
||||
/// Get a module variable.
|
||||
pub fn get_variable(&self, name: &str) -> Option<Dynamic> {
|
||||
self.variables.get(name).cloned()
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a module variable.
|
||||
pub fn get_variable_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
||||
self.variables.get_mut(name)
|
||||
}
|
||||
|
||||
/// Set a variable into the module.
|
||||
///
|
||||
/// If there is an existing variable of the same name, it is replaced.
|
||||
pub fn set_variable<K: Into<String>, T: Into<Dynamic>>(&mut self, name: K, value: T) {
|
||||
self.variables.insert(name.into(), value.into());
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a modules-qualified variable.
|
||||
pub(crate) fn get_qualified_variable_mut(
|
||||
&mut self,
|
||||
name: &str,
|
||||
modules: &StaticVec<(String, Position)>,
|
||||
pos: Position,
|
||||
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
||||
Ok(self
|
||||
.get_qualified_module_mut(modules)?
|
||||
.get_variable_mut(name)
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.into(), pos)))?)
|
||||
}
|
||||
|
||||
/// Does a sub-module exist in the module?
|
||||
pub fn contains_sub_module(&self, name: &str) -> bool {
|
||||
self.modules.contains_key(name)
|
||||
}
|
||||
|
||||
/// Get a sub-module.
|
||||
pub fn get_sub_module(&self, name: &str) -> Option<&Module> {
|
||||
self.modules.get(name)
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a sub-module.
|
||||
pub fn get_sub_module_mut(&mut self, name: &str) -> Option<&mut Module> {
|
||||
self.modules.get_mut(name)
|
||||
}
|
||||
|
||||
/// Set a sub-module into the module.
|
||||
///
|
||||
/// If there is an existing sub-module of the same name, it is replaced.
|
||||
pub fn set_sub_module<K: Into<String>>(&mut self, name: K, sub_module: Module) {
|
||||
self.modules.insert(name.into(), sub_module.into());
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a modules chain.
|
||||
/// The first module is always skipped and assumed to be the same as `self`.
|
||||
pub(crate) fn get_qualified_module_mut(
|
||||
&mut self,
|
||||
modules: &StaticVec<(String, Position)>,
|
||||
) -> Result<&mut Module, Box<EvalAltResult>> {
|
||||
let mut drain = modules.iter();
|
||||
drain.next().unwrap(); // Skip first module
|
||||
|
||||
let mut module = self;
|
||||
|
||||
for (id, id_pos) in drain {
|
||||
module = module
|
||||
.get_sub_module_mut(id)
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *id_pos)))?;
|
||||
}
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user