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 matching to a
11//! structural shape and contributes descriptive [`ShapeDoc`] metadata; the
12//! `stream_*_shape_symbol` accessors expose the stable [`Symbol`] under which
13//! each type's shape is registered.
14
15use 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
36/// Loadable library that registers the stream-core types as kernel shapes.
37///
38/// Implements [`Lib`]: its manifest exports one [`Export::Shape`] per stream
39/// type, and loading binds each export's [`Symbol`] to a documented shape value
40/// in the [`Linker`]. Prefer [`install_stream_core_shapes_lib`] for idempotent
41/// installation.
42pub 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
74/// Installs [`StreamCoreShapesLib`] into `cx`, skipping if already loaded.
75///
76/// Idempotent: returns `Ok(())` immediately when the library is already
77/// registered, otherwise loads it.
78pub 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
211/// Returns the registration symbol for the `StreamMetadata` shape.
212pub fn stream_metadata_shape_symbol() -> Symbol {
213    Symbol::qualified("stream", "Metadata")
214}
215
216/// Returns the registration symbol for the `StreamEnvelope` shape.
217pub fn stream_envelope_shape_symbol() -> Symbol {
218    Symbol::qualified("stream", "Envelope")
219}
220
221/// Returns the registration symbol for the `StreamMedia` shape.
222pub fn stream_media_shape_symbol() -> Symbol {
223    Symbol::qualified("stream", "Media")
224}
225
226/// Returns the registration symbol for the `ClockDomain` shape.
227pub fn stream_clock_domain_shape_symbol() -> Symbol {
228    Symbol::qualified("stream", "ClockDomain")
229}
230
231/// Returns the registration symbol for the `LatencyClass` shape.
232pub fn stream_latency_class_shape_symbol() -> Symbol {
233    Symbol::qualified("stream", "LatencyClass")
234}
235
236/// Returns the registration symbol for the `StreamCapability` shape.
237pub fn stream_capability_shape_symbol() -> Symbol {
238    Symbol::qualified("stream", "Capability")
239}
240
241/// Returns the registration symbol for the `BackpressureOutcome` shape.
242pub fn stream_backpressure_shape_symbol() -> Symbol {
243    Symbol::qualified("stream", "BackpressureOutcome")
244}
245
246/// Returns the registration symbol for the `StreamClock` shape.
247pub fn stream_clock_shape_symbol() -> Symbol {
248    Symbol::qualified("stream", "Clock")
249}
250
251/// Returns the registration symbol for the `StreamTempo` shape.
252pub fn stream_tempo_shape_symbol() -> Symbol {
253    Symbol::qualified("stream", "Tempo")
254}
255
256/// Returns the registration symbol for the `StreamBufferPolicy` shape.
257pub fn stream_buffer_policy_shape_symbol() -> Symbol {
258    Symbol::qualified("stream", "BufferPolicy")
259}
260
261/// Returns the registration symbol for the `StreamPacket` shape.
262pub fn stream_packet_shape_symbol() -> Symbol {
263    Symbol::qualified("stream", "Packet")
264}
265
266/// Returns the registration symbol for the `DataPacket` shape.
267pub fn stream_data_packet_shape_symbol() -> Symbol {
268    Symbol::qualified("stream", "DataPacket")
269}
270
271/// Returns the registration symbol for the `StreamDiagnostic` shape.
272pub 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}