mimium_lang/runtime.rs
1use crate::{
2 compiler::IoChannelInfo,
3 utils::{error::ReportableError, metadata::Location},
4};
5use thiserror::Error;
6
7pub mod ffi;
8pub mod ffi_serde;
9pub mod primitives;
10pub mod vm;
11pub mod vm_ffi;
12
13#[cfg(not(target_arch = "wasm32"))]
14pub mod wasm;
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub struct Time(pub u64);
17
18/// Return code from DSP execution (alias for vm::ReturnCode).
19pub type ReturnCode = i64;
20
21/// Type-safe representation of programs that can be hot-swapped into a runtime.
22///
23/// This replaces the previous `Box<dyn Any + Send>` approach with an explicit
24/// enum, providing compile-time type safety and eliminating runtime downcasts.
25pub enum ProgramPayload {
26 /// Native bytecode VM program.
27 VmProgram(vm::Program),
28 /// WASM module bytes with optional DSP state skeleton for state migration.
29 #[cfg(not(target_arch = "wasm32"))]
30 WasmModule {
31 bytes: Vec<u8>,
32 /// Preloaded WASM execution engine prepared on non-RT side.
33 /// RT side swaps this engine in without loading/instantiating the module.
34 prepared_engine: Box<crate::runtime::wasm::engine::WasmEngine>,
35 /// State tree skeleton of the DSP function in the new program.
36 /// When present, enables state-preserving hot-swap via
37 /// `state_tree::update_state_storage`.
38 dsp_state_skeleton: Option<state_tree::tree::StateTreeSkeleton<crate::mir::StateType>>,
39 /// Precomputed patch plan for migrating old state storage into
40 /// the new state layout.
41 state_patch_plan: state_tree::StateStoragePatchPlan,
42 /// Global state snapshot taken after running `main` on a
43 /// prewarmed runtime outside the audio thread.
44 prewarmed_global_state: Vec<u64>,
45 },
46}
47
48/// Abstraction over per-sample DSP execution backends.
49///
50/// This trait decouples audio drivers from a concrete runtime implementation,
51/// allowing both the native bytecode VM and the WASM backend to be used
52/// interchangeably with the same `Driver` infrastructure (cpal, CSV, etc.).
53pub trait DspRuntime {
54 /// Execute the DSP function for one sample tick.
55 fn run_dsp(&mut self, time: Time) -> ReturnCode;
56
57 /// Read the output produced by the last `run_dsp` call.
58 ///
59 /// The returned slice should contain at least `n_channels` elements.
60 fn get_output(&self, n_channels: usize) -> &[f64];
61
62 /// Write input samples that will be available during the next `run_dsp` call.
63 fn set_input(&mut self, input: &[f64]);
64
65 /// I/O channel configuration (None if the dsp function was not found).
66 fn io_channels(&self) -> Option<IoChannelInfo>;
67
68 /// Update sample rate for runtimes that keep an internal runtime state.
69 fn set_sample_rate(&mut self, _sample_rate: f64) {}
70
71 /// Attempt to hot-swap the running program.
72 ///
73 /// Takes a type-safe `ProgramPayload` which can be either a native VM
74 /// program or WASM module bytes. Returns `true` on success.
75 fn try_hot_swap(&mut self, new_program: ProgramPayload) -> bool {
76 let _ = new_program;
77 false
78 }
79
80 /// Upcast to `Any` so callers can downcast to a concrete runtime type.
81 fn as_any(&self) -> &dyn std::any::Any;
82 /// Mutable upcast to `Any`.
83 fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
84}
85
86#[derive(Debug, Error)]
87pub enum ErrorKind {
88 #[error("Unknown Error")]
89 Unknown,
90}
91
92#[derive(Debug, Error)]
93#[error("Runtime Error: {0}")]
94pub struct RuntimeError(pub ErrorKind, pub Location);
95
96impl ReportableError for RuntimeError {
97 fn get_labels(&self) -> Vec<(crate::utils::metadata::Location, String)> {
98 vec![(self.1.clone(), self.0.to_string())]
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 /// Compile-time assertion that `ProgramPayload` implements `Send`.
107 #[test]
108 fn ensure_payload_is_send() {
109 fn assert_send<T: Send>() {}
110 assert_send::<ProgramPayload>();
111 }
112}