1use sim_kernel::{
4 CapabilityName, Cx, Expr, Ref, Result, Symbol,
5 effect::{Effect, effect_abort_op_key, effect_resume_op_key, resolve_effect},
6};
7use sim_lib_stream_core::{BufferPolicy, StreamDirection, StreamMedia, StreamMetadata};
8
9use crate::capability::HostBackendCapability;
10
11pub fn stream_host_capability() -> CapabilityName {
13 CapabilityName::new("stream.host")
14}
15
16pub fn stream_host_device_read_effect_kind() -> Symbol {
18 Symbol::qualified("effect", "device-read")
19}
20
21pub fn stream_host_device_write_effect_kind() -> Symbol {
23 Symbol::qualified("effect", "device-write")
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct HostBackendInfo {
29 id: Symbol,
30 transport: Symbol,
31 media: StreamMedia,
32 hardware_required: bool,
33 callbacks_bounded: bool,
34 capabilities: Vec<HostBackendCapability>,
35}
36
37#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct HostDeviceSpec {
40 id: Symbol,
41 backend: Symbol,
42 media: StreamMedia,
43 direction: HostDirection,
44 clock: Symbol,
45 buffer: BufferPolicy,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum HostDirection {
51 Input,
53 Output,
55 Duplex,
57}
58
59#[derive(Clone, Debug, PartialEq, Eq)]
64pub struct HostOpenPlan {
65 backend: Symbol,
66 device: Symbol,
67 effect_kinds: Vec<Symbol>,
68 requires: Vec<CapabilityName>,
69}
70
71impl HostBackendInfo {
72 pub fn new(id: Symbol, transport: Symbol, media: StreamMedia, hardware_required: bool) -> Self {
74 Self {
75 id,
76 transport,
77 media,
78 hardware_required,
79 callbacks_bounded: true,
80 capabilities: Vec::new(),
81 }
82 }
83
84 pub fn with_capabilities(mut self, capabilities: Vec<HostBackendCapability>) -> Self {
86 self.capabilities = capabilities;
87 self
88 }
89
90 pub fn id(&self) -> &Symbol {
92 &self.id
93 }
94
95 pub fn transport(&self) -> &Symbol {
97 &self.transport
98 }
99
100 pub fn media(&self) -> StreamMedia {
102 self.media
103 }
104
105 pub fn hardware_required(&self) -> bool {
107 self.hardware_required
108 }
109
110 pub fn callbacks_bounded(&self) -> bool {
112 self.callbacks_bounded
113 }
114
115 pub fn capabilities(&self) -> &[HostBackendCapability] {
117 &self.capabilities
118 }
119
120 pub fn card_expr(&self) -> Expr {
122 Expr::Map(vec![
123 (
124 Expr::Symbol(Symbol::new("subject")),
125 Expr::Symbol(self.id.clone()),
126 ),
127 (
128 Expr::Symbol(Symbol::new("kind")),
129 Expr::Symbol(Symbol::qualified("stream", "host-backend")),
130 ),
131 (
132 Expr::Symbol(Symbol::new("transport")),
133 Expr::Symbol(self.transport.clone()),
134 ),
135 (
136 Expr::Symbol(Symbol::new("media")),
137 Expr::Symbol(self.media.symbol()),
138 ),
139 (
140 Expr::Symbol(Symbol::new("hardware-required")),
141 Expr::Bool(self.hardware_required),
142 ),
143 (
144 Expr::Symbol(Symbol::new("callbacks-bounded")),
145 Expr::Bool(self.callbacks_bounded),
146 ),
147 (
148 Expr::Symbol(Symbol::new("capabilities")),
149 Expr::List(
150 self.capabilities
151 .iter()
152 .map(|capability| Expr::Symbol(capability.symbol()))
153 .collect(),
154 ),
155 ),
156 ])
157 }
158}
159
160impl HostDeviceSpec {
161 pub fn new(
164 id: Symbol,
165 backend: Symbol,
166 media: StreamMedia,
167 direction: HostDirection,
168 clock: Symbol,
169 buffer: BufferPolicy,
170 ) -> Self {
171 Self {
172 id,
173 backend,
174 media,
175 direction,
176 clock,
177 buffer,
178 }
179 }
180
181 pub fn id(&self) -> &Symbol {
183 &self.id
184 }
185
186 pub fn backend(&self) -> &Symbol {
188 &self.backend
189 }
190
191 pub fn media(&self) -> StreamMedia {
193 self.media
194 }
195
196 pub fn direction(&self) -> HostDirection {
198 self.direction
199 }
200
201 pub fn clock(&self) -> &Symbol {
203 &self.clock
204 }
205
206 pub fn buffer(&self) -> &BufferPolicy {
208 &self.buffer
209 }
210
211 pub fn metadata(&self) -> StreamMetadata {
213 StreamMetadata::new(
214 self.id.clone(),
215 self.media,
216 self.direction.stream_direction(),
217 self.clock.clone(),
218 self.buffer.clone(),
219 )
220 }
221
222 pub fn open_plan(&self) -> HostOpenPlan {
224 HostOpenPlan {
225 backend: self.backend.clone(),
226 device: self.id.clone(),
227 effect_kinds: self.direction.effect_kinds(),
228 requires: vec![stream_host_capability()],
229 }
230 }
231
232 pub fn card_expr(&self) -> Expr {
234 Expr::Map(vec![
235 (
236 Expr::Symbol(Symbol::new("subject")),
237 Expr::Symbol(self.id.clone()),
238 ),
239 (
240 Expr::Symbol(Symbol::new("kind")),
241 Expr::Symbol(Symbol::qualified("stream", "host-device")),
242 ),
243 (
244 Expr::Symbol(Symbol::new("backend")),
245 Expr::Symbol(self.backend.clone()),
246 ),
247 (
248 Expr::Symbol(Symbol::new("media")),
249 Expr::Symbol(self.media.symbol()),
250 ),
251 (
252 Expr::Symbol(Symbol::new("direction")),
253 Expr::Symbol(self.direction.symbol()),
254 ),
255 (
256 Expr::Symbol(Symbol::new("clock")),
257 Expr::Symbol(self.clock.clone()),
258 ),
259 (Expr::Symbol(Symbol::new("buffer")), self.buffer.to_expr()),
260 ])
261 }
262}
263
264impl HostDirection {
265 pub fn stream_direction(self) -> StreamDirection {
267 match self {
268 Self::Input => StreamDirection::Source,
269 Self::Output => StreamDirection::Sink,
270 Self::Duplex => StreamDirection::Duplex,
271 }
272 }
273
274 pub fn symbol(self) -> Symbol {
276 match self {
277 Self::Input => Symbol::qualified("stream/host-direction", "input"),
278 Self::Output => Symbol::qualified("stream/host-direction", "output"),
279 Self::Duplex => Symbol::qualified("stream/host-direction", "duplex"),
280 }
281 }
282
283 pub fn effect_kinds(self) -> Vec<Symbol> {
285 match self {
286 Self::Input => vec![stream_host_device_read_effect_kind()],
287 Self::Output => vec![stream_host_device_write_effect_kind()],
288 Self::Duplex => vec![
289 stream_host_device_read_effect_kind(),
290 stream_host_device_write_effect_kind(),
291 ],
292 }
293 }
294}
295
296impl HostOpenPlan {
297 pub fn new(
300 backend: Symbol,
301 device: Symbol,
302 effect_kinds: Vec<Symbol>,
303 requires: Vec<CapabilityName>,
304 ) -> Self {
305 Self {
306 backend,
307 device,
308 effect_kinds,
309 requires,
310 }
311 }
312
313 pub fn backend(&self) -> &Symbol {
315 &self.backend
316 }
317
318 pub fn device(&self) -> &Symbol {
320 &self.device
321 }
322
323 pub fn effect_kinds(&self) -> &[Symbol] {
325 &self.effect_kinds
326 }
327
328 pub fn requires(&self) -> &[CapabilityName] {
330 &self.requires
331 }
332
333 pub fn enforce(&self, cx: &mut Cx) -> Result<()> {
336 for capability in &self.requires {
337 cx.require(capability)?;
338 }
339 for effect_kind in &self.effect_kinds {
340 let effect = Effect::new(
341 effect_kind.clone(),
342 Ref::Symbol(self.device.clone()),
343 Ref::Symbol(self.backend.clone()),
344 Ref::Symbol(Symbol::qualified("stream/host", "open-result")),
345 effect_resume_op_key(),
346 effect_abort_op_key(),
347 )
348 .with_requirements(self.requires.clone());
349 resolve_effect(cx, effect, |_cx, _effect| {
350 Ok(Ref::Symbol(Symbol::qualified(
351 "stream/host",
352 "open-authorized",
353 )))
354 })?;
355 }
356 Ok(())
357 }
358}