Skip to main content

yog_api/
interop.rs

1//! Inter-mod communication — export/import function pointers between mods.
2//!
3//! Uses the runtime's global symbol table (C ABI). Mods export typed function
4//! pointers under `"symbol"` names; other mods import them by qualified name
5//! `"mod_id:symbol"`.
6//!
7//! ## Example
8//!
9//! ```ignore
10//! // Mod A exports:
11//! fn register_pipe_impl(api: *const YogApi, registry: &mut Registry, def: ...) { ... }
12//! registry.interop().export("register_pipe", register_pipe_impl as *const c_void);
13//!
14//! // Mod B imports:
15//! type RegisterPipeFn = unsafe extern "C" fn(api: *const YogApi, ...);
16//! let func: RegisterPipeFn = registry.interop().import("yog-pipes:register_pipe").unwrap();
17//! unsafe { func(api_ptr, ...) };
18//! ```
19
20use std::os::raw::c_void;
21
22/// Safe wrapper around the runtime's inter-mod symbol table.
23///
24/// Returned by [`Registry::interop`](crate::Registry::interop).
25pub struct Interop {
26    api: *const crate::YogApi,
27}
28
29impl Interop {
30    pub(crate) fn new(api: *const crate::YogApi) -> Self {
31        Interop { api }
32    }
33
34    /// Export a function pointer under `symbol` for the current mod.
35    ///
36    /// The mod's ID is automatically determined from the manifest (passed
37    /// to `yog_mod_register` by the runtime).
38    pub fn export(&self, symbol: &str, ptr: *const c_void) {
39        let mod_id = crate::__current_mod_id().unwrap_or_else(|| "unknown".into());
40        unsafe {
41            let api = &*self.api;
42            let mid = yog_abi::YogStr::from_str(&mod_id);
43            let sym = yog_abi::YogStr::from_str(symbol);
44            (api.interop_export)(api.ctx, mid, sym, ptr);
45        }
46    }
47
48    /// Import a function pointer exported by `mod_id` under `symbol`.
49    ///
50    /// Use the qualified form `"mod_id:symbol"`:
51    ///
52    /// ```ignore
53    /// let ptr: *const c_void = interop.import("yog-pipes:register_pipe").unwrap();
54    /// ```
55    ///
56    /// Returns `None` if the symbol has not been exported (yet).
57    pub fn import_raw(&self, mod_id: &str, symbol: &str) -> Option<*const c_void> {
58        unsafe {
59            let api = &*self.api;
60            let mid = yog_abi::YogStr::from_str(mod_id);
61            let sym = yog_abi::YogStr::from_str(symbol);
62            let ptr = (api.interop_import)(api.ctx, mid, sym);
63            if ptr.is_null() { None } else { Some(ptr) }
64        }
65    }
66
67    /// Convenience: parse `"mod_id:symbol"` and import.
68    pub fn import(&self, qualified: &str) -> Option<*const c_void> {
69        let (mod_id, symbol) = qualified.split_once(':')?;
70        self.import_raw(mod_id, symbol)
71    }
72}