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
use std::any::Any;

use crate::error::Error;
use crate::ffi::InterpreterExtractError;
use crate::module;
use crate::sys;
use crate::value::Value;
use crate::Artichoke;

pub trait ModuleRegistry {
    fn def_module<T>(&mut self, spec: module::Spec) -> Result<(), Error>
    where
        T: Any;

    fn module_spec<T>(&self) -> Result<Option<&module::Spec>, Error>
    where
        T: Any;

    fn is_module_defined<T>(&self) -> bool
    where
        T: Any,
    {
        matches!(self.module_spec::<T>(), Ok(Some(_)))
    }

    fn module_of<T>(&mut self) -> Result<Option<Value>, Error>
    where
        T: Any;
}

impl ModuleRegistry for Artichoke {
    /// Create a module definition bound to a Rust type `T`.
    ///
    /// Module definitions have the same lifetime as the interpreter because the
    /// module def owns the `mrb_data_type` for the type, which must be
    /// long-lived.
    fn def_module<T>(&mut self, spec: module::Spec) -> Result<(), Error>
    where
        T: Any,
    {
        let state = self.state.as_mut().ok_or(InterpreterExtractError::new())?;
        state.modules.insert::<T>(Box::new(spec));
        Ok(())
    }

    /// Retrieve a module definition from the interpreter bound to Rust type `T`.
    ///
    /// This function returns `None` if type `T` has not had a module spec
    /// registered for it using [`ModuleRegistry::def_module`].
    fn module_spec<T>(&self) -> Result<Option<&module::Spec>, Error>
    where
        T: Any,
    {
        let state = self.state.as_ref().ok_or(InterpreterExtractError::new())?;
        let spec = state.modules.get::<T>();
        Ok(spec)
    }

    fn module_of<T>(&mut self) -> Result<Option<Value>, Error>
    where
        T: Any,
    {
        let state = self.state.as_ref().ok_or(InterpreterExtractError::new())?;
        let spec = state.modules.get::<T>();
        let spec = if let Some(spec) = spec {
            spec
        } else {
            return Ok(None);
        };
        let rclass = spec.rclass();
        let rclass = unsafe { self.with_ffi_boundary(|mrb| rclass.resolve(mrb))? };
        if let Some(mut rclass) = rclass {
            let module = unsafe { sys::mrb_sys_module_value(rclass.as_mut()) };
            let module = Value::from(module);
            Ok(Some(module))
        } else {
            Ok(None)
        }
    }
}