1use sim_kernel::{
4 CapabilityName, Expr, Symbol,
5 effect::{effect_device_read_kind, effect_device_write_kind},
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
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct HostBackendInfo {
19 id: Symbol,
20 transport: Symbol,
21 media: StreamMedia,
22 hardware_required: bool,
23 callbacks_bounded: bool,
24 capabilities: Vec<HostBackendCapability>,
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct HostDeviceSpec {
30 id: Symbol,
31 backend: Symbol,
32 media: StreamMedia,
33 direction: HostDirection,
34 clock: Symbol,
35 buffer: BufferPolicy,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub enum HostDirection {
41 Input,
43 Output,
45 Duplex,
47}
48
49#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct HostOpenPlan {
55 backend: Symbol,
56 device: Symbol,
57 effect_kind: Symbol,
58 requires: Vec<CapabilityName>,
59}
60
61impl HostBackendInfo {
62 pub fn new(id: Symbol, transport: Symbol, media: StreamMedia, hardware_required: bool) -> Self {
64 Self {
65 id,
66 transport,
67 media,
68 hardware_required,
69 callbacks_bounded: true,
70 capabilities: Vec::new(),
71 }
72 }
73
74 pub fn with_capabilities(mut self, capabilities: Vec<HostBackendCapability>) -> Self {
76 self.capabilities = capabilities;
77 self
78 }
79
80 pub fn id(&self) -> &Symbol {
82 &self.id
83 }
84
85 pub fn transport(&self) -> &Symbol {
87 &self.transport
88 }
89
90 pub fn media(&self) -> StreamMedia {
92 self.media
93 }
94
95 pub fn hardware_required(&self) -> bool {
97 self.hardware_required
98 }
99
100 pub fn callbacks_bounded(&self) -> bool {
102 self.callbacks_bounded
103 }
104
105 pub fn capabilities(&self) -> &[HostBackendCapability] {
107 &self.capabilities
108 }
109
110 pub fn card_expr(&self) -> Expr {
112 Expr::Map(vec![
113 (
114 Expr::Symbol(Symbol::new("subject")),
115 Expr::Symbol(self.id.clone()),
116 ),
117 (
118 Expr::Symbol(Symbol::new("kind")),
119 Expr::Symbol(Symbol::qualified("stream", "host-backend")),
120 ),
121 (
122 Expr::Symbol(Symbol::new("transport")),
123 Expr::Symbol(self.transport.clone()),
124 ),
125 (
126 Expr::Symbol(Symbol::new("media")),
127 Expr::Symbol(self.media.symbol()),
128 ),
129 (
130 Expr::Symbol(Symbol::new("hardware-required")),
131 Expr::Bool(self.hardware_required),
132 ),
133 (
134 Expr::Symbol(Symbol::new("callbacks-bounded")),
135 Expr::Bool(self.callbacks_bounded),
136 ),
137 (
138 Expr::Symbol(Symbol::new("capabilities")),
139 Expr::List(
140 self.capabilities
141 .iter()
142 .map(|capability| Expr::Symbol(capability.symbol()))
143 .collect(),
144 ),
145 ),
146 ])
147 }
148}
149
150impl HostDeviceSpec {
151 pub fn new(
154 id: Symbol,
155 backend: Symbol,
156 media: StreamMedia,
157 direction: HostDirection,
158 clock: Symbol,
159 buffer: BufferPolicy,
160 ) -> Self {
161 Self {
162 id,
163 backend,
164 media,
165 direction,
166 clock,
167 buffer,
168 }
169 }
170
171 pub fn id(&self) -> &Symbol {
173 &self.id
174 }
175
176 pub fn backend(&self) -> &Symbol {
178 &self.backend
179 }
180
181 pub fn media(&self) -> StreamMedia {
183 self.media
184 }
185
186 pub fn direction(&self) -> HostDirection {
188 self.direction
189 }
190
191 pub fn clock(&self) -> &Symbol {
193 &self.clock
194 }
195
196 pub fn buffer(&self) -> &BufferPolicy {
198 &self.buffer
199 }
200
201 pub fn metadata(&self) -> StreamMetadata {
203 StreamMetadata::new(
204 self.id.clone(),
205 self.media,
206 self.direction.stream_direction(),
207 self.clock.clone(),
208 self.buffer.clone(),
209 )
210 }
211
212 pub fn open_plan(&self) -> HostOpenPlan {
214 HostOpenPlan {
215 backend: self.backend.clone(),
216 device: self.id.clone(),
217 effect_kind: self.direction.effect_kind(),
218 requires: vec![stream_host_capability()],
219 }
220 }
221
222 pub fn card_expr(&self) -> Expr {
224 Expr::Map(vec![
225 (
226 Expr::Symbol(Symbol::new("subject")),
227 Expr::Symbol(self.id.clone()),
228 ),
229 (
230 Expr::Symbol(Symbol::new("kind")),
231 Expr::Symbol(Symbol::qualified("stream", "host-device")),
232 ),
233 (
234 Expr::Symbol(Symbol::new("backend")),
235 Expr::Symbol(self.backend.clone()),
236 ),
237 (
238 Expr::Symbol(Symbol::new("media")),
239 Expr::Symbol(self.media.symbol()),
240 ),
241 (
242 Expr::Symbol(Symbol::new("direction")),
243 Expr::Symbol(self.direction.symbol()),
244 ),
245 (
246 Expr::Symbol(Symbol::new("clock")),
247 Expr::Symbol(self.clock.clone()),
248 ),
249 (Expr::Symbol(Symbol::new("buffer")), self.buffer.to_expr()),
250 ])
251 }
252}
253
254impl HostDirection {
255 pub fn stream_direction(self) -> StreamDirection {
257 match self {
258 Self::Input => StreamDirection::Source,
259 Self::Output => StreamDirection::Sink,
260 Self::Duplex => StreamDirection::Duplex,
261 }
262 }
263
264 pub fn symbol(self) -> Symbol {
266 match self {
267 Self::Input => Symbol::qualified("stream/host-direction", "input"),
268 Self::Output => Symbol::qualified("stream/host-direction", "output"),
269 Self::Duplex => Symbol::qualified("stream/host-direction", "duplex"),
270 }
271 }
272
273 pub fn effect_kind(self) -> Symbol {
276 match self {
277 Self::Input => effect_device_read_kind(),
278 Self::Output | Self::Duplex => effect_device_write_kind(),
279 }
280 }
281}
282
283impl HostOpenPlan {
284 pub fn backend(&self) -> &Symbol {
286 &self.backend
287 }
288
289 pub fn device(&self) -> &Symbol {
291 &self.device
292 }
293
294 pub fn effect_kind(&self) -> &Symbol {
296 &self.effect_kind
297 }
298
299 pub fn requires(&self) -> &[CapabilityName] {
301 &self.requires
302 }
303}