mimium_lang/
plugin.rs

1//! # Plugin System for mimium
2//! In order to extend mimium's capability to communicate between host system, mimium has its own FFI system.
3//! The FFI is done through some traits in this plugin module in order to decouple dependencies(modules may depends on external crates).
4//! There are 3 types of interfaces you need to define depending on what you need.
5//!
6//! 1. **IO Plugins** Sets of instance-free external functions such as `print` and `println`. They are mostly for glue functions for host system's IO. `mimium-core` is an example of this type of module.
7//! 2. **External Unit Generator(UGen) Plugin.** If you need to define native Unit Generator, use `UGenPlugin` interface. In mimium code, you need to call higher-order function that returns instance of the UGen. You need to write small wrapper for this which simply calls object's constructor (In the future, this wrapper will be automatically implemented through proc-macro). Multiple instances may exist at the same time. `mimium-symphonia` is a example of this type of module.
8//! 3. **System Plugin**. If your plugin needs to mutate states of system-wide instance (1 plugin instance per 1 vm), you need to implement `SystemPlugin` traits. System plugin can have callbacks invoked at the important timings of the system like `on_init`, `before_on_sample` & so on. Internal synchronous event scheduler is implemented through this plugins system. `mimium-rand` is also an example of this type of module.
9
10mod builtin_functins;
11mod system_plugin;
12pub use builtin_functins::get_builtin_fns_as_plugins;
13use std::{cell::RefCell, rc::Rc};
14
15pub use system_plugin::{
16    DynSystemPlugin, SysPluginSignature, SystemPlugin, SystemPluginAudioWorker, SystemPluginFnType,
17    SystemPluginMacroType,
18};
19
20use crate::{
21    compiler::EvalStage,
22    interner::{Symbol, TypeNodeId},
23    interpreter::Value,
24    vm::{Machine, ReturnCode},
25};
26trait EvalStageT {
27    fn get_stage() -> EvalStage;
28}
29trait MacroStageT {}
30trait MachineStageT {}
31trait PersistentStageT: MacroStageT + MachineStageT {}
32trait ExternalFunction {
33    /// Declare the type signature of the external function.
34    fn get_type_info(&self) -> TypeNodeId;
35    fn get_name(&self) -> Symbol;
36    type Stage: EvalStageT;
37}
38struct MacroStage {}
39impl EvalStageT for MacroStage {
40    fn get_stage() -> EvalStage {
41        EvalStage::Stage(0)
42    }
43}
44impl MacroStageT for MacroStage {}
45struct MachineStage;
46impl EvalStageT for MachineStage {
47    fn get_stage() -> EvalStage {
48        EvalStage::Stage(1)
49    }
50}
51impl MachineStageT for MachineStage {}
52struct PersistentStage;
53impl EvalStageT for PersistentStage {
54    fn get_stage() -> EvalStage {
55        EvalStage::Persistent
56    }
57}
58impl MacroStageT for PersistentStage {}
59impl MachineStageT for PersistentStage {}
60impl PersistentStageT for PersistentStage {}
61pub type MacroFunType = Rc<RefCell<dyn Fn(&[(Value, TypeNodeId)]) -> Value>>;
62pub trait MacroFunction {
63    //name is still needed for linking program
64    fn get_name(&self) -> Symbol;
65    fn get_type(&self) -> TypeNodeId;
66    /// Main macro function. If you need to receive 2 or more arguments, you need to pass struct or tuple as the argument instead.
67    fn get_fn(&self) -> MacroFunType;
68}
69pub type ExtFunType = fn(&mut Machine) -> ReturnCode;
70pub type ExtClsType = Rc<RefCell<dyn FnMut(&mut Machine) -> ReturnCode>>;
71pub trait MachineFunction {
72    //name is still needed for linking program
73    fn get_name(&self) -> Symbol;
74    /// Main function that will be called by the machine.
75    fn get_fn(&self) -> ExtClsType;
76}
77#[derive(Clone)]
78pub struct MacroInfo {
79    pub name: Symbol,
80    pub ty: TypeNodeId,
81    pub fun: MacroFunType,
82}
83impl MacroInfo {
84    pub fn new(name: Symbol, ty: TypeNodeId, fun: MacroFunType) -> Self {
85        Self { name, ty, fun }
86    }
87}
88impl ExternalFunction for MacroInfo {
89    type Stage = MacroStage;
90    fn get_type_info(&self) -> TypeNodeId {
91        self.ty
92    }
93    fn get_name(&self) -> Symbol {
94        self.name
95    }
96}
97impl MacroFunction for MacroInfo {
98    fn get_name(&self) -> Symbol {
99        self.name
100    }
101    fn get_type(&self) -> TypeNodeId {
102        self.ty
103    }
104    fn get_fn(&self) -> MacroFunType {
105        self.fun.clone()
106    }
107}
108
109#[derive(Clone, Debug)]
110pub struct ExtFunInfo {
111    pub name: Symbol,
112    pub ty: TypeNodeId,
113    pub fun: ExtFunType,
114}
115impl ExtFunInfo {
116    pub fn new(name: Symbol, ty: TypeNodeId, fun: ExtFunType) -> Self {
117        Self { name, ty, fun }
118    }
119}
120impl ExternalFunction for ExtFunInfo {
121    type Stage = MachineStage;
122    fn get_type_info(&self) -> TypeNodeId {
123        self.ty
124    }
125    fn get_name(&self) -> Symbol {
126        self.name
127    }
128}
129impl MachineFunction for ExtFunInfo {
130    fn get_name(&self) -> Symbol {
131        self.name
132    }
133    fn get_fn(&self) -> ExtClsType {
134        Rc::new(RefCell::new(self.fun))
135    }
136}
137
138#[derive(Clone)]
139pub struct ExtClsInfo {
140    pub name: Symbol,
141    pub ty: TypeNodeId,
142    pub fun: ExtClsType,
143}
144impl ExtClsInfo {
145    pub fn new(name: Symbol, ty: TypeNodeId, fun: ExtClsType) -> Self {
146        Self { name, ty, fun }
147    }
148}
149impl From<ExtClsInfo> for ExtFunTypeInfo {
150    fn from(info: ExtClsInfo) -> Self {
151        ExtFunTypeInfo {
152            name: info.name,
153            ty: info.ty,
154            stage: MachineStage::get_stage(),
155        }
156    }
157}
158impl From<ExtFunInfo> for ExtFunTypeInfo {
159    fn from(info: ExtFunInfo) -> Self {
160        ExtFunTypeInfo {
161            name: info.name,
162            ty: info.ty,
163            stage: MachineStage::get_stage(),
164        }
165    }
166}
167impl ExternalFunction for ExtClsInfo {
168    type Stage = MachineStage;
169    fn get_type_info(&self) -> TypeNodeId {
170        self.ty
171    }
172    fn get_name(&self) -> Symbol {
173        self.name
174    }
175}
176impl MachineFunction for ExtClsInfo {
177    fn get_name(&self) -> Symbol {
178        self.name
179    }
180    fn get_fn(&self) -> ExtClsType {
181        self.fun.clone()
182    }
183}
184
185#[derive(Clone)]
186pub struct CommonFunction {
187    name: Symbol,
188    ty: TypeNodeId,
189    macro_fun: fn(&[(Value, TypeNodeId)]) -> Value,
190    fun: ExtFunType,
191}
192impl ExternalFunction for CommonFunction {
193    type Stage = PersistentStage;
194    fn get_type_info(&self) -> TypeNodeId {
195        self.ty
196    }
197    fn get_name(&self) -> Symbol {
198        self.name
199    }
200}
201impl MachineFunction for CommonFunction {
202    fn get_name(&self) -> Symbol {
203        self.name
204    }
205    fn get_fn(&self) -> ExtClsType {
206        Rc::new(RefCell::new(self.fun))
207    }
208}
209impl MacroFunction for CommonFunction {
210    fn get_name(&self) -> Symbol {
211        self.name
212    }
213    fn get_type(&self) -> TypeNodeId {
214        self.ty
215    }
216    fn get_fn(&self) -> MacroFunType {
217        Rc::new(RefCell::new(self.macro_fun))
218    }
219}
220#[derive(Clone, Copy)]
221pub struct ExtFunTypeInfo {
222    pub name: Symbol,
223    pub ty: TypeNodeId,
224    pub stage: EvalStage,
225}
226impl ExtFunTypeInfo {
227    pub fn new(name: Symbol, ty: TypeNodeId, stage: EvalStage) -> Self {
228        Self { name, ty, stage }
229    }
230}
231pub trait Plugin {
232    fn get_macro_functions(&self) -> Vec<Box<dyn MacroFunction>>;
233    fn get_ext_closures(&self) -> Vec<Box<dyn MachineFunction>>;
234
235    //limitation: if the functin contains persistent functions, you have to override this method.
236    fn get_type_infos(&self) -> Vec<ExtFunTypeInfo>;
237}
238
239#[derive(Clone)]
240pub struct InstantPlugin {
241    pub macros: Vec<MacroInfo>,
242    pub extcls: Vec<ExtClsInfo>,
243    pub commonfns: Vec<CommonFunction>,
244}
245impl Plugin for InstantPlugin {
246    // type MacroT = MacroInfo;
247    // type MachineT = ExtClsInfo;
248
249    fn get_macro_functions(&self) -> Vec<Box<dyn MacroFunction>> {
250        let macros = self
251            .macros
252            .clone()
253            .into_iter()
254            .map(|m| Box::new(m) as Box<dyn MacroFunction>);
255        let commons = self
256            .commonfns
257            .clone()
258            .into_iter()
259            .map(|c| Box::new(c) as Box<dyn MacroFunction>);
260        macros.chain(commons).collect()
261    }
262
263    fn get_ext_closures(&self) -> Vec<Box<dyn MachineFunction>> {
264        let extfns = self
265            .extcls
266            .clone()
267            .into_iter()
268            .map(|e| Box::new(e) as Box<dyn MachineFunction>);
269        let commons = self
270            .commonfns
271            .clone()
272            .into_iter()
273            .map(|c| Box::new(c) as Box<dyn MachineFunction>);
274        extfns.chain(commons).collect()
275    }
276
277    fn get_type_infos(&self) -> Vec<ExtFunTypeInfo> {
278        let macros = self
279            .macros
280            .iter()
281            .map(|m| ExtFunTypeInfo::new(m.name, m.ty, MacroStage::get_stage()));
282        let extcls = self
283            .extcls
284            .iter()
285            .map(|e| ExtFunTypeInfo::new(e.name, e.ty, MachineStage::get_stage()));
286        let commons = self
287            .commonfns
288            .iter()
289            .map(|c| ExtFunTypeInfo::new(c.name, c.ty, PersistentStage::get_stage()));
290        macros.chain(extcls).chain(commons).collect()
291    }
292}
293
294/// Todo: Make wrapper macro for auto impl `Plugin`
295pub trait UGenPlugin {
296    type InitParam;
297    type Args;
298    type Ret;
299    fn new(param: Self::InitParam) -> Self;
300    fn on_sample(&mut self, arg: Self::Args) -> Self::Ret;
301}
302// type DynUgenPlugin{}
303// pub type UGenPluginCollection(Vec<DynUGenPlugin>);
304// impl Plugin for UGenPluginCollection{}
305
306pub fn get_extfun_types(plugins: &[Box<dyn Plugin>]) -> impl Iterator<Item = ExtFunTypeInfo> + '_ {
307    plugins
308        .iter()
309        .flat_map(|plugin| plugin.get_type_infos().into_iter())
310}
311
312pub fn get_macro_functions(
313    plugins: &[Box<dyn Plugin>],
314) -> impl Iterator<Item = Box<dyn MacroFunction>> + '_ {
315    plugins
316        .iter()
317        .flat_map(|plugin| plugin.get_macro_functions().into_iter())
318}
319pub fn get_ext_closures(
320    plugins: &[Box<dyn Plugin>],
321) -> impl Iterator<Item = Box<dyn MachineFunction>> + '_ {
322    plugins
323        .iter()
324        .flat_map(|plugin| plugin.get_ext_closures().into_iter())
325}