sim_lib_stream_host/
registry.rs1use std::{collections::BTreeMap, sync::Arc};
4
5use sim_kernel::{Cx, Error, Expr, Result, Symbol};
6
7use crate::{
8 HostBackend, HostDeviceInventory, HostOpenPlan, HostOpenStream, HostStreamConfigRequest,
9 missing_capability_card_expr,
10};
11
12#[derive(Default)]
14pub struct HostBackendRegistry {
15 backends: BTreeMap<Symbol, Arc<dyn HostBackend>>,
16}
17
18impl HostBackendRegistry {
19 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn register<B>(&mut self, backend: B) -> Result<()>
26 where
27 B: HostBackend + 'static,
28 {
29 self.register_arc(Arc::new(backend))
30 }
31
32 pub fn register_arc(&mut self, backend: Arc<dyn HostBackend>) -> Result<()> {
34 let id = backend.info().id().clone();
35 if self.backends.contains_key(&id) {
36 return Err(Error::Eval(format!(
37 "stream host backend {id} is already registered"
38 )));
39 }
40 self.backends.insert(id, backend);
41 Ok(())
42 }
43
44 pub fn backend(&self, id: &Symbol) -> Option<Arc<dyn HostBackend>> {
46 self.backends.get(id).cloned()
47 }
48
49 pub fn enumerate(&self) -> Result<Vec<HostDeviceInventory>> {
51 self.backends
52 .values()
53 .map(|backend| backend.enumerate())
54 .collect()
55 }
56
57 pub fn plan_open(&self, request: &HostStreamConfigRequest) -> Result<HostOpenPlan> {
59 let backend = self.backend_or_error(request.backend())?;
60 let inventory = backend.enumerate()?;
61 let device = inventory
62 .devices()
63 .iter()
64 .find(|device| device.id() == request.device())
65 .ok_or_else(|| {
66 Error::Eval(format!(
67 "stream host backend {} has no device {}",
68 request.backend(),
69 request.device()
70 ))
71 })?;
72 if device.media() != request.media() {
73 return Err(Error::TypeMismatch {
74 expected: "request media matching host device",
75 found: "request media for another host device",
76 });
77 }
78 if device.direction() != request.direction() {
79 return Err(Error::TypeMismatch {
80 expected: "request direction matching host device",
81 found: "request direction for another host device",
82 });
83 }
84 Ok(device.open_plan())
85 }
86
87 pub fn open_checked(
90 &self,
91 cx: &mut Cx,
92 request: HostStreamConfigRequest,
93 ) -> Result<HostOpenStream> {
94 self.plan_open(&request)?.enforce(cx)?;
95 self.open(request)
96 }
97
98 pub fn open(&self, request: HostStreamConfigRequest) -> Result<HostOpenStream> {
104 self.plan_open(&request)?;
105 let backend = self.backend_or_error(request.backend())?;
106 backend.open(request)
107 }
108
109 fn backend_or_error(&self, backend: &Symbol) -> Result<Arc<dyn HostBackend>> {
110 self.backends
111 .get(backend)
112 .cloned()
113 .ok_or_else(|| Error::Eval(format!("stream host backend {backend} is not registered")))
114 }
115
116 pub fn card_exprs(&self) -> Result<Vec<Expr>> {
118 let mut cards = Vec::new();
119 for backend in self.backends.values() {
120 cards.push(backend.info().card_expr());
121 cards.extend(backend.enumerate()?.card_exprs());
122 }
123 Ok(cards)
124 }
125
126 pub fn missing_capability_card(
128 &self,
129 backend: &Symbol,
130 capability: crate::HostBackendCapability,
131 ) -> Expr {
132 missing_capability_card_expr(backend, capability)
133 }
134}