1use std::sync::Arc;
16
17use sim_kernel::{
18 AbiVersion, Cx, Export, Expr, Lib, LibManifest, LibTarget, Linker, Result, ShapeRef, Symbol,
19 Value, Version,
20};
21use sim_shape::{Shape, ShapeDoc, ShapeMatch, shape_value};
22
23#[path = "shape/structural.rs"]
24mod structural;
25
26use structural::{
27 backpressure_shape, buffer_policy_shape, capability_shape, clock_domain_shape, clock_shape,
28 data_packet_shape, diagnostic_shape, envelope_shape, latency_class_shape, media_shape,
29 metadata_shape, packet_shape, tempo_shape,
30};
31
32const STREAM_CORE_SHAPES_LIB_ID: &str = "stream-core-shapes";
33
34type ShapeSpec = (Symbol, &'static str, Vec<&'static str>, Arc<dyn Shape>);
35
36pub struct StreamCoreShapesLib;
43
44impl Lib for StreamCoreShapesLib {
45 fn manifest(&self) -> LibManifest {
46 LibManifest {
47 id: Symbol::new(STREAM_CORE_SHAPES_LIB_ID),
48 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
49 abi: AbiVersion { major: 0, minor: 1 },
50 target: LibTarget::HostRegistered,
51 requires: Vec::new(),
52 capabilities: Vec::new(),
53 exports: shape_specs()
54 .into_iter()
55 .map(|(symbol, _, _, _)| Export::Shape {
56 symbol,
57 shape_id: None,
58 })
59 .collect(),
60 }
61 }
62
63 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
64 for (symbol, name, details, inner) in shape_specs() {
65 linker.shape_value(
66 symbol.clone(),
67 shape_value(symbol, Arc::new(DocumentedShape::new(name, details, inner))),
68 )?;
69 }
70 Ok(())
71 }
72}
73
74pub fn install_stream_core_shapes_lib(cx: &mut Cx) -> Result<()> {
79 if cx
80 .registry()
81 .lib(&Symbol::new(STREAM_CORE_SHAPES_LIB_ID))
82 .is_some()
83 {
84 return Ok(());
85 }
86 cx.load_lib(&StreamCoreShapesLib).map(|_| ())
87}
88
89fn shape_specs() -> Vec<ShapeSpec> {
90 vec![
91 (
92 stream_metadata_shape_symbol(),
93 "StreamMetadata",
94 vec![
95 "stream metadata read-construct surface",
96 "fields: id, media, direction, clock, buffer",
97 ],
98 metadata_shape(),
99 ),
100 (
101 stream_envelope_shape_symbol(),
102 "StreamEnvelope",
103 vec![
104 "versioned stream packet envelope",
105 "fields: stream id, packet id, media, direction, sequence, ticks, primary clock domain, clock domains, profile, diagnostics, packet",
106 ],
107 envelope_shape(),
108 ),
109 (
110 stream_media_shape_symbol(),
111 "StreamMedia",
112 vec![
113 "stream media symbol used by metadata",
114 "known media include pcm, midi, diagnostic, and data",
115 ],
116 media_shape(),
117 ),
118 (
119 stream_clock_domain_shape_symbol(),
120 "ClockDomain",
121 vec![
122 "shared timing vocabulary for envelopes, stream descriptors, and placement",
123 "known domains include sample, block, control, midi-tick, wall, transport, server-frame, browser-frame, trace-step, and job",
124 ],
125 clock_domain_shape(),
126 ),
127 (
128 stream_latency_class_shape_symbol(),
129 "LatencyClass",
130 vec![
131 "shared latency vocabulary for streams and placement",
132 "known classes include offline-render, block-local, interactive, sample-exact, buffered-preview, collab-bardelay, and remote-collaboration",
133 ],
134 latency_class_shape(),
135 ),
136 (
137 stream_capability_shape_symbol(),
138 "StreamCapability",
139 vec![
140 "stream transport capability flags",
141 "known flags include exact, deterministic, realtime, bounded, remote, replayable, preview, persistent, resumable, and lossy",
142 ],
143 capability_shape(),
144 ),
145 (
146 stream_backpressure_shape_symbol(),
147 "BackpressureOutcome",
148 vec![
149 "shared stream queue outcome vocabulary",
150 "known outcomes include accepted, dropped-newest, dropped-oldest, blocked, timed-out, rejected, and closed",
151 ],
152 backpressure_shape(),
153 ),
154 (
155 stream_clock_shape_symbol(),
156 "StreamClock",
157 vec![
158 "clock chart descriptor shared by frame and MIDI indexes",
159 "kernel stream events carry kernel Tick values",
160 ],
161 clock_shape(),
162 ),
163 (
164 stream_tempo_shape_symbol(),
165 "StreamTempo",
166 vec![
167 "tempo map descriptor for MIDI clock conversion",
168 "segments require a tick-zero anchor and increasing ticks",
169 ],
170 tempo_shape(),
171 ),
172 (
173 stream_buffer_policy_shape_symbol(),
174 "StreamBufferPolicy",
175 vec![
176 "bounded stream buffer policy",
177 "capacity plus overflow behavior map",
178 ],
179 buffer_policy_shape(),
180 ),
181 (
182 stream_packet_shape_symbol(),
183 "StreamPacket",
184 vec![
185 "tagged packet map for PCM, MIDI, diagnostics, and data",
186 "codec round trips preserve packet tags and payload fields",
187 ],
188 packet_shape(),
189 ),
190 (
191 stream_data_packet_shape_symbol(),
192 "DataPacket",
193 vec![
194 "generic runtime data packet",
195 "fields: packet stream/packet/data, kind symbol, payload expr",
196 ],
197 data_packet_shape(),
198 ),
199 (
200 stream_diagnostic_shape_symbol(),
201 "StreamDiagnostic",
202 vec![
203 "diagnostic packet payload",
204 "kind symbol plus message string",
205 ],
206 diagnostic_shape(),
207 ),
208 ]
209}
210
211pub fn stream_metadata_shape_symbol() -> Symbol {
213 Symbol::qualified("stream", "Metadata")
214}
215
216pub fn stream_envelope_shape_symbol() -> Symbol {
218 Symbol::qualified("stream", "Envelope")
219}
220
221pub fn stream_media_shape_symbol() -> Symbol {
223 Symbol::qualified("stream", "Media")
224}
225
226pub fn stream_clock_domain_shape_symbol() -> Symbol {
228 Symbol::qualified("stream", "ClockDomain")
229}
230
231pub fn stream_latency_class_shape_symbol() -> Symbol {
233 Symbol::qualified("stream", "LatencyClass")
234}
235
236pub fn stream_capability_shape_symbol() -> Symbol {
238 Symbol::qualified("stream", "Capability")
239}
240
241pub fn stream_backpressure_shape_symbol() -> Symbol {
243 Symbol::qualified("stream", "BackpressureOutcome")
244}
245
246pub fn stream_clock_shape_symbol() -> Symbol {
248 Symbol::qualified("stream", "Clock")
249}
250
251pub fn stream_tempo_shape_symbol() -> Symbol {
253 Symbol::qualified("stream", "Tempo")
254}
255
256pub fn stream_buffer_policy_shape_symbol() -> Symbol {
258 Symbol::qualified("stream", "BufferPolicy")
259}
260
261pub fn stream_packet_shape_symbol() -> Symbol {
263 Symbol::qualified("stream", "Packet")
264}
265
266pub fn stream_data_packet_shape_symbol() -> Symbol {
268 Symbol::qualified("stream", "DataPacket")
269}
270
271pub fn stream_diagnostic_shape_symbol() -> Symbol {
273 Symbol::qualified("stream", "Diagnostic")
274}
275
276struct DocumentedShape {
277 name: &'static str,
278 details: Vec<&'static str>,
279 inner: Arc<dyn Shape>,
280}
281
282impl DocumentedShape {
283 fn new(name: &'static str, details: Vec<&'static str>, inner: Arc<dyn Shape>) -> Self {
284 Self {
285 name,
286 details,
287 inner,
288 }
289 }
290}
291
292impl Shape for DocumentedShape {
293 fn parents(&self, cx: &mut Cx) -> Result<Vec<ShapeRef>> {
294 self.inner.parents(cx)
295 }
296
297 fn is_effectful(&self) -> bool {
298 self.inner.is_effectful()
299 }
300
301 fn is_total(&self) -> bool {
302 self.inner.is_total()
303 }
304
305 fn is_subshape_of(&self, cx: &mut Cx, parent: &dyn Shape) -> Result<Option<bool>> {
306 self.inner.is_subshape_of(cx, parent)
307 }
308
309 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
310 self.inner.check_value(cx, value)
311 }
312
313 fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
314 self.inner.check_expr(cx, expr)
315 }
316
317 fn describe(&self, _cx: &mut Cx) -> Result<ShapeDoc> {
318 let mut doc = ShapeDoc::new(self.name);
319 for detail in &self.details {
320 doc = doc.with_detail(*detail);
321 }
322 Ok(doc)
323 }
324}