Skip to main content

openlogi_device/
channel.rs

1//! HID++ transport and channel lifecycle.
2//!
3//! Resolving a [`route::DeviceRoute`] to an open channel, and the strategies
4//! that keep one open: [`ChannelPool`] for sessions that open on demand,
5//! [`ChannelRegistry`] for channels owned by the inventory enumerator, and
6//! [`SharedChannel`] handles lent out to this crate's read/write entry points.
7//!
8//! Opening itself belongs to a [`crate::backend::HidBackend`]; nothing here
9//! names a HID stack.
10
11use std::sync::Arc;
12
13use hidpp::channel::HidppChannel;
14
15use route::DeviceRoute;
16
17pub(crate) mod pool;
18pub(crate) mod registry;
19pub(crate) mod route;
20#[cfg(test)]
21pub(crate) mod scripted;
22
23pub use pool::ChannelPool;
24pub use registry::ChannelRegistry;
25
26/// An open HID++ channel to a device, shared so route-addressed reads and writes
27/// can reuse an inventory- or capture-owned connection instead of
28/// re-enumerating and opening a fresh channel each time (which costs ~100ms+).
29///
30/// Cheap to clone (an `Arc` plus the [`DeviceRoute`] it points at). Built by
31/// the inventory registry or a standalone capture session.
32#[derive(Clone)]
33pub struct SharedChannel {
34    channel: Arc<HidppChannel>,
35    route: DeviceRoute,
36}
37
38impl SharedChannel {
39    /// Wrap an open channel that reaches `route`.
40    #[must_use]
41    pub(crate) fn new(channel: Arc<HidppChannel>, route: DeviceRoute) -> Self {
42        Self { channel, route }
43    }
44
45    /// Whether this channel reaches `route` — so the write path only reuses it
46    /// for the device it actually points at.
47    #[must_use]
48    pub fn matches(&self, route: &DeviceRoute) -> bool {
49        self.route == *route
50    }
51
52    pub(crate) fn channel(&self) -> &Arc<HidppChannel> {
53        &self.channel
54    }
55
56    pub(crate) fn device_index(&self) -> u8 {
57        self.route.device_index()
58    }
59}