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
35#[derive(Clone)]
37pub struct BackendFactory {
38 ctors: HashMap<&'static str, BackendCtor>,
39 cache: HashMap<String, BackendParts>,
40}
41
42impl BackendFactory {
43 pub fn new() -> Self {
45 Self {
46 ctors: HashMap::new(),
47 cache: HashMap::new(),
48 }
49 }
50
51 pub fn register(&mut self, name: &'static str, ctor: BackendCtor) {
53 self.ctors.insert(name, ctor);
54 }
55
56 fn get_or_create(
58 &mut self,
59 name: &str,
60 params: &HashMap<String, ParamValue>,
61 ) -> Result<BackendParts, String> {
62 if let Some(cached) = self.cache.get(name) {
63 return Ok(cached.clone());
64 }
65 let ctor = self
66 .ctors
67 .get(name)
68 .ok_or_else(|| format!("unknown backend: {name}"))?;
69 let result = ctor(params)?;
70 self.cache.insert(name.to_string(), result.clone());
71 Ok(result)
72 }
73
74 pub fn create_any(
77 &mut self,
78 name: &str,
79 params: &HashMap<String, ParamValue>,
80 ) -> Result<BackendParts, String> {
81 self.get_or_create(name, params)
82 }
83
84 pub fn create_output(
86 &mut self,
87 name: &str,
88 params: &HashMap<String, ParamValue>,
89 ) -> Result<OutputBundle, String> {
90 let (driver, _capture, playback) = self.get_or_create(name, params)?;
91 Ok(OutputBundle {
92 driver,
93 playback: playback
94 .ok_or_else(|| format!("backend '{name}' does not support output"))?,
95 })
96 }
97
98 pub fn create_input(
100 &mut self,
101 name: &str,
102 params: &HashMap<String, ParamValue>,
103 ) -> Result<InputBundle, String> {
104 let (driver, capture, _playback) = self.get_or_create(name, params)?;
105 Ok(InputBundle {
106 driver,
107 capture: capture.ok_or_else(|| format!("backend '{name}' does not support input"))?,
108 })
109 }
110
111 pub fn contains(&self, name: &str) -> bool {
113 self.ctors.contains_key(name)
114 }
115}
116
117impl Default for BackendFactory {
118 fn default() -> Self {
119 Self::new()
120 }
121}