openlogi_device/channel/
pool.rs1use std::sync::{Arc, Weak};
4
5use hidpp::channel::HidppChannel;
6use tokio::sync::Mutex;
7
8use crate::backend::{BackendError, HidBackend};
9use crate::channel::route::{DeviceRoute, open_route_channel};
10
11#[derive(Clone)]
13pub struct ChannelPool {
14 backend: Arc<dyn HidBackend>,
17 entries: Arc<Mutex<Vec<PoolEntry>>>,
18}
19
20struct PoolEntry {
21 route: DeviceRoute,
22 channel: Weak<HidppChannel>,
23}
24
25impl ChannelPool {
26 #[must_use]
28 pub fn with_backend(backend: Arc<dyn HidBackend>) -> Self {
29 Self {
30 backend,
31 entries: Arc::new(Mutex::new(Vec::new())),
32 }
33 }
34
35 pub async fn open(
37 &self,
38 route: &DeviceRoute,
39 ) -> Result<Option<Arc<HidppChannel>>, BackendError> {
40 let mut entries = self.entries.lock().await;
41 entries.retain(|entry| entry.channel.strong_count() > 0);
42 if let Some(channel) = entries.iter().find_map(|entry| {
43 entry
44 .route
45 .shares_transport(route)
46 .then(|| entry.channel.upgrade())
47 .flatten()
48 }) {
49 return Ok(Some(channel));
50 }
51 let Some(channel) = open_route_channel(&*self.backend, route).await? else {
52 return Ok(None);
53 };
54 entries.push(PoolEntry {
55 route: route.clone(),
56 channel: Arc::downgrade(&channel),
57 });
58 Ok(Some(channel))
59 }
60}