rill_graph/
backend_factory.rs1use std::collections::HashMap;
4use std::sync::Arc;
5
6use rill_core::io::{IoCapture, IoDriver, IoPlayback};
7use rill_core::traits::ParamValue;
8
9pub type BackendParts = (
11 Arc<dyn IoDriver>,
12 Option<Arc<dyn IoCapture>>,
13 Option<Arc<dyn IoPlayback>>,
14);
15
16pub type BackendCtor = fn(params: &HashMap<String, ParamValue>) -> Result<BackendParts, String>;
18
19pub struct OutputBundle {
21 pub driver: Arc<dyn IoDriver>,
23 pub playback: Arc<dyn IoPlayback>,
25}
26
27pub struct InputBundle {
29 pub driver: Arc<dyn IoDriver>,
31 pub capture: Arc<dyn IoCapture>,
33}
34
35pub struct DuplexBundle {
37 pub driver: Arc<dyn IoDriver>,
39 pub capture: Arc<dyn IoCapture>,
41 pub playback: Arc<dyn IoPlayback>,
43}
44
45#[derive(Clone)]
47pub struct BackendFactory {
48 ctors: HashMap<&'static str, BackendCtor>,
49 cache: HashMap<String, BackendParts>,
50}
51
52impl BackendFactory {
53 pub fn new() -> Self {
55 Self {
56 ctors: HashMap::new(),
57 cache: HashMap::new(),
58 }
59 }
60
61 pub fn register(&mut self, name: &'static str, ctor: BackendCtor) {
63 self.ctors.insert(name, ctor);
64 }
65
66 fn get_or_create(
68 &mut self,
69 name: &str,
70 params: &HashMap<String, ParamValue>,
71 ) -> Result<BackendParts, String> {
72 if let Some(cached) = self.cache.get(name) {
73 return Ok(cached.clone());
74 }
75 let ctor = self
76 .ctors
77 .get(name)
78 .ok_or_else(|| format!("unknown backend: {name}"))?;
79 let result = ctor(params)?;
80 self.cache.insert(name.to_string(), result.clone());
81 Ok(result)
82 }
83
84 pub fn create_any(
87 &mut self,
88 name: &str,
89 params: &HashMap<String, ParamValue>,
90 ) -> Result<BackendParts, String> {
91 self.get_or_create(name, params)
92 }
93
94 pub fn create_output(
96 &mut self,
97 name: &str,
98 params: &HashMap<String, ParamValue>,
99 ) -> Result<OutputBundle, String> {
100 let (driver, _capture, playback) = self.get_or_create(name, params)?;
101 Ok(OutputBundle {
102 driver,
103 playback: playback
104 .ok_or_else(|| format!("backend '{name}' does not support output"))?,
105 })
106 }
107
108 pub fn create_input(
110 &mut self,
111 name: &str,
112 params: &HashMap<String, ParamValue>,
113 ) -> Result<InputBundle, String> {
114 let (driver, capture, _playback) = self.get_or_create(name, params)?;
115 Ok(InputBundle {
116 driver,
117 capture: capture.ok_or_else(|| format!("backend '{name}' does not support input"))?,
118 })
119 }
120
121 pub fn create_duplex(
123 &mut self,
124 name: &str,
125 params: &HashMap<String, ParamValue>,
126 ) -> Result<DuplexBundle, String> {
127 let (driver, capture, playback) = self.get_or_create(name, params)?;
128 Ok(DuplexBundle {
129 driver,
130 capture: capture.ok_or_else(|| format!("backend '{name}' does not support input"))?,
131 playback: playback
132 .ok_or_else(|| format!("backend '{name}' does not support output"))?,
133 })
134 }
135
136 pub fn contains(&self, name: &str) -> bool {
138 self.ctors.contains_key(name)
139 }
140}
141
142impl Default for BackendFactory {
143 fn default() -> Self {
144 Self::new()
145 }
146}