1use sim_kernel::{
2 Cx, ExportKind, ExportRecord, ExportState, Lib, LibManifest, Linker, LoadCx, Result, RuntimeId,
3 Symbol,
4};
5use sim_lib_core::{SurfaceField, SurfacePackLib, SurfacePackSpec, SurfaceValueSpec, install_once};
6
7const MIDI_IO_LIB_ID: &str = "midi-io";
8const SOURCE_EXPORT_KIND: &str = "MidiSourceFactory";
9const SINK_EXPORT_KIND: &str = "MidiSinkFactory";
10const TRACKED_SOURCE_EXPORT_KIND: &str = "TrackedMidiSourceFactory";
11const REGISTRY_SYMBOL_NAME: &str = "MidiIoRegistry";
12
13pub struct MidiIoLib;
16
17impl Lib for MidiIoLib {
18 fn manifest(&self) -> LibManifest {
19 midi_io_pack().manifest()
20 }
21
22 fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
23 midi_io_pack().load(cx, linker)
24 }
25}
26
27pub fn install_midi_io_lib(cx: &mut Cx) -> Result<()> {
32 if !install_once(cx, &MidiIoLib)? {
33 return Ok(());
34 }
35 let lib = Symbol::new(MIDI_IO_LIB_ID);
36 for symbol in source_symbols() {
37 cx.registry_mut().append_export_record(
38 &lib,
39 ExportRecord {
40 kind: ExportKind::named(SOURCE_EXPORT_KIND),
41 symbol,
42 state: ExportState::Resolved {
43 id: RuntimeId::Value,
44 },
45 },
46 )?;
47 }
48 for symbol in sink_symbols() {
49 cx.registry_mut().append_export_record(
50 &lib,
51 ExportRecord {
52 kind: ExportKind::named(SINK_EXPORT_KIND),
53 symbol,
54 state: ExportState::Resolved {
55 id: RuntimeId::Value,
56 },
57 },
58 )?;
59 }
60 for symbol in tracked_source_symbols() {
61 cx.registry_mut().append_export_record(
62 &lib,
63 ExportRecord {
64 kind: ExportKind::named(TRACKED_SOURCE_EXPORT_KIND),
65 symbol,
66 state: ExportState::Resolved {
67 id: RuntimeId::Value,
68 },
69 },
70 )?;
71 }
72 Ok(())
73}
74
75fn source_symbols() -> Vec<Symbol> {
76 vec![Symbol::qualified("midi", "MemoryMidiSource")]
77}
78
79fn sink_symbols() -> Vec<Symbol> {
80 vec![Symbol::qualified("midi", "MemoryMidiSink")]
81}
82
83fn tracked_source_symbols() -> Vec<Symbol> {
84 vec![Symbol::qualified("midi", "MemoryTrackedMidiSource")]
85}
86
87fn io_symbols() -> Vec<Symbol> {
88 let mut symbols = source_symbols();
89 symbols.extend(sink_symbols());
90 symbols.extend(tracked_source_symbols());
91 symbols
92}
93
94fn registry_symbol() -> Symbol {
95 Symbol::qualified("midi", REGISTRY_SYMBOL_NAME)
96}
97
98fn io_value_spec(symbol: Symbol) -> SurfaceValueSpec {
99 let (shape, mode) = match symbol.name.as_ref() {
100 "MemoryMidiSource" => (
101 Symbol::qualified("midi", "MidiSourceFactory"),
102 "in-memory source",
103 ),
104 "MemoryMidiSink" => (
105 Symbol::qualified("midi", "MidiSinkFactory"),
106 "in-memory sink",
107 ),
108 "MemoryTrackedMidiSource" => (
109 Symbol::qualified("midi", "TrackedMidiSourceFactory"),
110 "in-memory tracked source",
111 ),
112 _ => (Symbol::qualified("midi", "MidiSourceFactory"), "unknown"),
113 };
114 SurfaceValueSpec {
115 symbol: symbol.clone(),
116 fields: vec![
117 (Symbol::new("symbol"), SurfaceField::Symbol(symbol)),
118 (Symbol::new("layer"), SurfaceField::Str("midi".to_owned())),
119 (Symbol::new("kind"), SurfaceField::Str("plugin".to_owned())),
120 (Symbol::new("shape"), SurfaceField::Symbol(shape)),
121 (
122 Symbol::new("dependencies"),
123 SurfaceField::Strs(vec!["midi-core".to_owned()]),
124 ),
125 (Symbol::new("lossless"), SurfaceField::Bool(true)),
126 (Symbol::new("capabilities"), SurfaceField::Symbols(vec![])),
127 (Symbol::new("mode"), SurfaceField::Str(mode.to_owned())),
128 ],
129 }
130}
131
132fn registry_value_spec() -> SurfaceValueSpec {
133 SurfaceValueSpec {
134 symbol: registry_symbol(),
135 fields: vec![
136 (
137 Symbol::new("symbol"),
138 SurfaceField::Symbol(registry_symbol()),
139 ),
140 (Symbol::new("layer"), SurfaceField::Str("midi".to_owned())),
141 (Symbol::new("kind"), SurfaceField::Str("plugin".to_owned())),
142 (
143 Symbol::new("shape"),
144 SurfaceField::Symbol(Symbol::qualified("midi", "MidiSourceFactory")),
145 ),
146 (Symbol::new("dependencies"), SurfaceField::Symbols(vec![])),
147 (Symbol::new("lossless"), SurfaceField::Bool(true)),
148 (Symbol::new("capabilities"), SurfaceField::Symbols(vec![])),
149 (
150 Symbol::new("sources"),
151 SurfaceField::Symbols(source_symbols()),
152 ),
153 (Symbol::new("sinks"), SurfaceField::Symbols(sink_symbols())),
154 (
155 Symbol::new("tracked-sources"),
156 SurfaceField::Symbols(tracked_source_symbols()),
157 ),
158 ],
159 }
160}
161
162fn midi_io_pack() -> SurfacePackLib {
163 let mut values: Vec<SurfaceValueSpec> = io_symbols().into_iter().map(io_value_spec).collect();
164 values.push(registry_value_spec());
165 SurfacePackLib {
166 spec: SurfacePackSpec {
167 lib_id: Symbol::new(MIDI_IO_LIB_ID),
168 values,
169 },
170 }
171}