Skip to main content

memlink_runtime/
instance.rs

1//! Module instance - a loaded and callable module.
2
3use std::path::{Path, PathBuf};
4use std::sync::Arc;
5
6use crate::arena::Arena;
7use crate::error::{Error, Result};
8use crate::ffi::symbols::{LibHandle, ModuleSymbols};
9use crate::mhash::fnv1a_hash;
10use crate::panic::{safe_call_unchecked, setup_panic_hook};
11
12#[derive(Debug, Clone, Default)]
13pub struct ModuleProfile {
14    pub name: Option<String>,
15}
16
17struct ModuleInstanceInner {
18    #[allow(dead_code)]
19    handle: LibHandle,
20    _symbols: ModuleSymbols<'static>,
21}
22
23pub struct ModuleInstance {
24    inner: Arc<ModuleInstanceInner>,
25    path: PathBuf,
26    arena: Arena,
27    profile: ModuleProfile,
28}
29
30unsafe impl Send for ModuleInstance {}
31unsafe impl Sync for ModuleInstance {}
32
33impl ModuleInstance {
34    pub(crate) fn new(handle: LibHandle, symbols: ModuleSymbols, path: PathBuf) -> Self {
35        setup_panic_hook();
36
37        let symbols = unsafe {
38            std::mem::transmute::<ModuleSymbols<'_>, ModuleSymbols<'static>>(symbols)
39        };
40
41        ModuleInstance {
42            inner: Arc::new(ModuleInstanceInner {
43                handle,
44                _symbols: symbols,
45            }),
46            path,
47            arena: Arena::with_default_capacity(),
48            profile: ModuleProfile::default(),
49        }
50    }
51
52    pub fn path(&self) -> &Path {
53        &self.path
54    }
55
56    pub fn profile(&self) -> &ModuleProfile {
57        &self.profile
58    }
59
60    pub fn arena(&self) -> &Arena {
61        &self.arena
62    }
63
64    fn symbols(&self) -> &ModuleSymbols<'static> {
65        &self.inner._symbols
66    }
67
68    pub fn init(&self, config: &[u8]) -> Result<()> {
69        safe_call_unchecked(|| {
70            let result = unsafe { (self.symbols().memlink_init)(config.as_ptr(), config.len()) };
71
72            if result == 0 {
73                Ok(())
74            } else {
75                Err(Error::ModuleCallFailed(result))
76            }
77        })?
78    }
79
80    pub fn call(&self, method: &str, args: &[u8]) -> Result<Vec<u8>> {
81        let method_id = fnv1a_hash(method);
82        let mut output = vec![0u8; 4096];
83
84        safe_call_unchecked(|| {
85            let result = unsafe {
86                (self.symbols().memlink_call)(method_id, args.as_ptr(), args.len(), output.as_mut_ptr())
87            };
88
89            if result == 0 {
90                Ok(output)
91            } else {
92                Err(Error::ModuleCallFailed(result))
93            }
94        })?
95    }
96
97    pub fn shutdown(&self) -> Result<()> {
98        safe_call_unchecked(|| {
99            let result = unsafe { (self.symbols().memlink_shutdown)() };
100
101            if result == 0 {
102                Ok(())
103            } else {
104                Err(Error::ModuleCallFailed(result))
105            }
106        })?
107    }
108}
109
110impl Clone for ModuleInstance {
111    fn clone(&self) -> Self {
112        ModuleInstance {
113            inner: Arc::clone(&self.inner),
114            path: self.path.clone(),
115            arena: self.arena.clone(),
116            profile: self.profile.clone(),
117        }
118    }
119}
120
121impl std::fmt::Debug for ModuleInstance {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        f.debug_struct("ModuleInstance")
124            .field("path", &self.path)
125            .field("profile", &self.profile)
126            .finish()
127    }
128}
129
130impl Drop for ModuleInstance {
131    fn drop(&mut self) {
132        let _ = self.shutdown();
133    }
134}