mimium_lang/plugin/
system_plugin.rs1use super::ExtClsInfo;
8use crate::{
9 compiler::EvalStage,
10 interner::{ToSymbol, TypeNodeId},
11 interpreter::Value,
12 plugin::MacroInfo,
13 runtime::{
14 Time,
15 vm::{Machine, ReturnCode},
16 },
17};
18use std::{
19 any::Any,
20 cell::{RefCell, UnsafeCell},
21 rc::Rc,
22 sync::Arc,
23};
24pub type SystemPluginFnType<T> = fn(&mut T, &mut Machine) -> ReturnCode;
25pub type SystemPluginMacroType<T> = fn(&mut T, &[(Value, TypeNodeId)]) -> Value;
26
27pub struct SysPluginSignature {
32 name: &'static str,
33 fun: Rc<dyn Any>,
36 ty: TypeNodeId,
37 stage: EvalStage,
41}
42impl SysPluginSignature {
43 pub fn new<F, T>(name: &'static str, fun: F, ty: TypeNodeId) -> Self
44 where
45 F: Fn(&mut T, &mut Machine) -> ReturnCode + 'static,
46 T: SystemPlugin,
47 {
48 Self {
49 name,
50 fun: Rc::new(fun),
51 ty,
52 stage: EvalStage::Stage(1),
53 }
54 }
55 pub fn new_macro<F, T>(name: &'static str, fun: F, ty: TypeNodeId) -> Self
56 where
57 F: Fn(&mut T, &[(Value, TypeNodeId)]) -> Value + 'static,
58 T: SystemPlugin,
59 {
60 Self {
61 name,
62 fun: Rc::new(fun),
63 ty,
64 stage: EvalStage::Stage(0),
65 }
66 }
67}
68
69pub trait SystemPlugin {
75 fn generate_audioworker(&mut self) -> Option<Box<dyn SystemPluginAudioWorker>> {
76 None
77 }
78 fn on_init(&mut self, _machine: &mut Machine) -> ReturnCode {
79 0
80 }
81 fn after_main(&mut self, _machine: &mut Machine) -> ReturnCode {
82 0
83 }
84 fn gen_interfaces(&self) -> Vec<SysPluginSignature>;
85 fn try_get_main_loop(&mut self) -> Option<Box<dyn FnOnce()>> {
86 None
87 }
88}
89
90pub trait SystemPluginAudioWorker {
91 fn on_sample(&mut self, _time: Time, _machine: &mut Machine) -> ReturnCode {
92 0
93 }
94 fn gen_interfaces(&self) -> Vec<SysPluginSignature>;
95}
96
97pub struct DynSystemPlugin {
99 pub inner: Arc<UnsafeCell<dyn SystemPlugin>>,
100 audioworker: Option<Box<dyn SystemPluginAudioWorker>>,
101 pub clsinfos: Vec<ExtClsInfo>,
102 pub macroinfos: Vec<MacroInfo>,
103}
104
105impl DynSystemPlugin{
106 pub fn take_audioworker(&mut self) -> Option<Box<dyn SystemPluginAudioWorker>> {
107 self.audioworker.take()
108 }
109}
110impl<T> From<T> for DynSystemPlugin
116where
117 T: SystemPlugin + Sized + 'static,
118{
119 fn from(mut plugin: T) -> Self {
120 let mut audioworker = plugin.generate_audioworker();
121
122 let ifs = plugin.gen_interfaces();
123 let inner = Arc::new(UnsafeCell::new(plugin));
124 let macroinfos = ifs
125 .iter()
126 .filter(|&SysPluginSignature { stage, .. }| matches!(stage, EvalStage::Stage(0)))
127 .map(|SysPluginSignature { name, fun, ty, .. }| {
128 let inner = inner.clone();
129 let fun = fun
130 .clone()
131 .downcast::<SystemPluginMacroType<T>>()
132 .expect("invalid conversion applied in the system plugin resolution.");
133 MacroInfo::new(
134 name.to_symbol(),
135 *ty,
136 Rc::new(RefCell::new(move |args: &[(Value, TypeNodeId)]| -> Value {
137 unsafe {
140 let p = inner.get().as_mut().unwrap();
141 fun(p, args)
142 }
143 })),
144 )
145 })
146 .collect();
147 let clsinfos = ifs
148 .into_iter()
149 .chain(
150 audioworker
151 .as_mut()
152 .map(|worker| worker.gen_interfaces())
153 .into_iter()
154 .flatten(),
155 )
156 .filter(|SysPluginSignature { stage, .. }| matches!(stage, EvalStage::Stage(1)))
157 .map(|SysPluginSignature { name, fun, ty, .. }| {
158 let inner = inner.clone();
159 let fun = fun
160 .clone()
161 .downcast::<SystemPluginFnType<T>>()
162 .expect("invalid conversion applied in the system plugin resolution.");
163 let fun = Rc::new(RefCell::new(move |machine: &mut Machine| -> ReturnCode {
164 unsafe {
167 let p = inner.get().as_mut().unwrap();
168 fun(p, machine)
169 }
170 }));
171 ExtClsInfo::new(name.to_symbol(), ty, fun)
172 })
173 .collect();
174 DynSystemPlugin {
175 inner,
176 audioworker,
177 clsinfos,
178 macroinfos,
179 }
180 }
181}
182