Skip to main content

sim_lib_stream_core/
shape.rs

1//! Shape protocol integration for the stream-core types.
2//!
3//! The kernel defines the [`Shape`] protocol -- its one shared engine for
4//! parsing, checking, binding, and dispatch. This module supplies the concrete
5//! behavior of registering stream-core's types as first-class shape targets
6//! without redefining that contract: [`StreamCoreShapesLib`] is a loadable
7//! [`Lib`] that exports one named shape per stream type, and
8//! [`install_stream_core_shapes_lib`] loads it idempotently into a [`Cx`].
9//!
10//! Each registered shape is a `DocumentedShape` that delegates all matching
11//! to the kernel's total [`AnyShape`] and contributes only descriptive
12//! [`ShapeDoc`] metadata; the `stream_*_shape_symbol` accessors expose the
13//! stable [`Symbol`] under which each type's shape is registered.
14
15use std::sync::Arc;
16
17use sim_kernel::{
18    AbiVersion, Cx, Export, Lib, LibManifest, LibTarget, Linker, Result, Symbol, Version,
19};
20use sim_shape::{AnyShape, Shape, ShapeDoc, shape_value};
21
22const STREAM_CORE_SHAPES_LIB_ID: &str = "stream-core-shapes";
23
24/// Loadable library that registers the stream-core types as kernel shapes.
25///
26/// Implements [`Lib`]: its manifest exports one [`Export::Shape`] per stream
27/// type, and loading binds each export's [`Symbol`] to a documented shape value
28/// in the [`Linker`]. Prefer [`install_stream_core_shapes_lib`] for idempotent
29/// installation.
30pub struct StreamCoreShapesLib;
31
32impl Lib for StreamCoreShapesLib {
33    fn manifest(&self) -> LibManifest {
34        LibManifest {
35            id: Symbol::new(STREAM_CORE_SHAPES_LIB_ID),
36            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
37            abi: AbiVersion { major: 0, minor: 1 },
38            target: LibTarget::HostRegistered,
39            requires: Vec::new(),
40            capabilities: Vec::new(),
41            exports: shape_specs()
42                .into_iter()
43                .map(|(symbol, _, _)| Export::Shape {
44                    symbol,
45                    shape_id: None,
46                })
47                .collect(),
48        }
49    }
50
51    fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
52        for (symbol, name, details) in shape_specs() {
53            linker.shape_value(
54                symbol.clone(),
55                shape_value(symbol, Arc::new(DocumentedShape::new(name, details))),
56            )?;
57        }
58        Ok(())
59    }
60}
61
62/// Installs [`StreamCoreShapesLib`] into `cx`, skipping if already loaded.
63///
64/// Idempotent: returns `Ok(())` immediately when the library is already
65/// registered, otherwise loads it.
66pub fn install_stream_core_shapes_lib(cx: &mut Cx) -> Result<()> {
67    if cx
68        .registry()
69        .lib(&Symbol::new(STREAM_CORE_SHAPES_LIB_ID))
70        .is_some()
71    {
72        return Ok(());
73    }
74    cx.load_lib(&StreamCoreShapesLib).map(|_| ())
75}
76
77fn shape_specs() -> Vec<(Symbol, &'static str, Vec<&'static str>)> {
78    vec![
79        (
80            stream_metadata_shape_symbol(),
81            "StreamMetadata",
82            vec![
83                "stream metadata read-construct surface",
84                "fields: id, media, direction, clock, buffer",
85            ],
86        ),
87        (
88            stream_envelope_shape_symbol(),
89            "StreamEnvelope",
90            vec![
91                "versioned stream packet envelope",
92                "fields: stream id, packet id, media, direction, sequence, ticks, primary clock domain, clock domains, profile, diagnostics, packet",
93            ],
94        ),
95        (
96            stream_media_shape_symbol(),
97            "StreamMedia",
98            vec![
99                "stream media symbol used by metadata",
100                "known media include pcm, midi, diagnostic, and data",
101            ],
102        ),
103        (
104            stream_clock_domain_shape_symbol(),
105            "ClockDomain",
106            vec![
107                "shared timing vocabulary for envelopes, stream descriptors, and placement",
108                "known domains include sample, block, control, midi-tick, wall, transport, server-frame, browser-frame, trace-step, and job",
109            ],
110        ),
111        (
112            stream_latency_class_shape_symbol(),
113            "LatencyClass",
114            vec![
115                "shared latency vocabulary for streams and placement",
116                "known classes include offline-render, block-local, interactive, sample-exact, buffered-preview, collab-bardelay, and remote-collaboration",
117            ],
118        ),
119        (
120            stream_capability_shape_symbol(),
121            "StreamCapability",
122            vec![
123                "stream transport capability flags",
124                "known flags include exact, deterministic, realtime, bounded, remote, replayable, preview, persistent, resumable, and lossy",
125            ],
126        ),
127        (
128            stream_backpressure_shape_symbol(),
129            "BackpressureOutcome",
130            vec![
131                "shared stream queue outcome vocabulary",
132                "known outcomes include accepted, dropped-newest, dropped-oldest, blocked, timed-out, rejected, and closed",
133            ],
134        ),
135        (
136            stream_clock_shape_symbol(),
137            "StreamClock",
138            vec![
139                "clock chart descriptor shared by frame and MIDI indexes",
140                "kernel stream events still carry KERNEL 6 Tick values",
141            ],
142        ),
143        (
144            stream_tempo_shape_symbol(),
145            "StreamTempo",
146            vec![
147                "tempo map descriptor for MIDI clock conversion",
148                "segments require a tick-zero anchor and increasing ticks",
149            ],
150        ),
151        (
152            stream_buffer_policy_shape_symbol(),
153            "StreamBufferPolicy",
154            vec![
155                "bounded stream buffer policy",
156                "capacity plus overflow behavior map",
157            ],
158        ),
159        (
160            stream_packet_shape_symbol(),
161            "StreamPacket",
162            vec![
163                "tagged packet map for PCM, MIDI, diagnostics, and data",
164                "codec round trips preserve packet tags and payload fields",
165            ],
166        ),
167        (
168            stream_data_packet_shape_symbol(),
169            "DataPacket",
170            vec![
171                "generic runtime data packet",
172                "fields: packet stream/packet/data, kind symbol, payload expr",
173            ],
174        ),
175        (
176            stream_diagnostic_shape_symbol(),
177            "StreamDiagnostic",
178            vec![
179                "diagnostic packet payload",
180                "kind symbol plus message string",
181            ],
182        ),
183    ]
184}
185
186/// Returns the registration symbol for the `StreamMetadata` shape.
187pub fn stream_metadata_shape_symbol() -> Symbol {
188    Symbol::qualified("stream", "Metadata")
189}
190
191/// Returns the registration symbol for the `StreamEnvelope` shape.
192pub fn stream_envelope_shape_symbol() -> Symbol {
193    Symbol::qualified("stream", "Envelope")
194}
195
196/// Returns the registration symbol for the `StreamMedia` shape.
197pub fn stream_media_shape_symbol() -> Symbol {
198    Symbol::qualified("stream", "Media")
199}
200
201/// Returns the registration symbol for the `ClockDomain` shape.
202pub fn stream_clock_domain_shape_symbol() -> Symbol {
203    Symbol::qualified("stream", "ClockDomain")
204}
205
206/// Returns the registration symbol for the `LatencyClass` shape.
207pub fn stream_latency_class_shape_symbol() -> Symbol {
208    Symbol::qualified("stream", "LatencyClass")
209}
210
211/// Returns the registration symbol for the `StreamCapability` shape.
212pub fn stream_capability_shape_symbol() -> Symbol {
213    Symbol::qualified("stream", "Capability")
214}
215
216/// Returns the registration symbol for the `BackpressureOutcome` shape.
217pub fn stream_backpressure_shape_symbol() -> Symbol {
218    Symbol::qualified("stream", "BackpressureOutcome")
219}
220
221/// Returns the registration symbol for the `StreamClock` shape.
222pub fn stream_clock_shape_symbol() -> Symbol {
223    Symbol::qualified("stream", "Clock")
224}
225
226/// Returns the registration symbol for the `StreamTempo` shape.
227pub fn stream_tempo_shape_symbol() -> Symbol {
228    Symbol::qualified("stream", "Tempo")
229}
230
231/// Returns the registration symbol for the `StreamBufferPolicy` shape.
232pub fn stream_buffer_policy_shape_symbol() -> Symbol {
233    Symbol::qualified("stream", "BufferPolicy")
234}
235
236/// Returns the registration symbol for the `StreamPacket` shape.
237pub fn stream_packet_shape_symbol() -> Symbol {
238    Symbol::qualified("stream", "Packet")
239}
240
241/// Returns the registration symbol for the `DataPacket` shape.
242pub fn stream_data_packet_shape_symbol() -> Symbol {
243    Symbol::qualified("stream", "DataPacket")
244}
245
246/// Returns the registration symbol for the `StreamDiagnostic` shape.
247pub fn stream_diagnostic_shape_symbol() -> Symbol {
248    Symbol::qualified("stream", "Diagnostic")
249}
250
251struct DocumentedShape {
252    name: &'static str,
253    details: Vec<&'static str>,
254}
255
256impl DocumentedShape {
257    fn new(name: &'static str, details: Vec<&'static str>) -> Self {
258        Self { name, details }
259    }
260}
261
262impl Shape for DocumentedShape {
263    fn is_total(&self) -> bool {
264        AnyShape.is_total()
265    }
266
267    fn check_value(
268        &self,
269        cx: &mut sim_kernel::Cx,
270        value: sim_kernel::Value,
271    ) -> Result<sim_shape::ShapeMatch> {
272        AnyShape.check_value(cx, value)
273    }
274
275    fn check_expr(
276        &self,
277        cx: &mut sim_kernel::Cx,
278        expr: &sim_kernel::Expr,
279    ) -> Result<sim_shape::ShapeMatch> {
280        AnyShape.check_expr(cx, expr)
281    }
282
283    fn describe(&self, _cx: &mut sim_kernel::Cx) -> Result<ShapeDoc> {
284        let mut doc = ShapeDoc::new(self.name);
285        for detail in &self.details {
286            doc = doc.with_detail(*detail);
287        }
288        Ok(doc)
289    }
290}