diff options
| author | jamie <git@skilet.ro> | 2026-08-29 22:51:38 +0100 |
|---|---|---|
| committer | jamie <git@skilet.ro> | 2026-08-29 22:55:36 +0100 |
| commit | 6ade07db214e8571a439b474e6c4e6a4c861d098 (patch) | |
| tree | 0c4864b5d4a2abc0b05cfdb83596d87edb018dac /src/protocol.rs | |
| parent | 4c42e8c9d7ec1b2e94267038d5ee38a714ca2955 (diff) | |
Diffstat (limited to 'src/protocol.rs')
| -rw-r--r-- | src/protocol.rs | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/src/protocol.rs b/src/protocol.rs index d6fce5f..39afac0 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -62,7 +62,8 @@ pub enum Transition { } /// Builds the link query output report (report id `0x3a` + payload). -pub fn link_query_frame() -> [u8; LINK_QUERY_LEN] { +#[must_use] +pub const fn link_query_frame() -> [u8; LINK_QUERY_LEN] { let mut frame = [0u8; LINK_QUERY_LEN]; frame[0] = reports::OUT_60_C; frame[1] = CMD_PREFIX[0]; @@ -73,19 +74,29 @@ pub fn link_query_frame() -> [u8; LINK_QUERY_LEN] { /// True if `data` is a link-status response report (`0x3c` echoing the /// query selector). -pub fn is_link_response(data: &[u8]) -> bool { - data.len() >= 2 && data[0] == LINK_RESPONSE_REPORT && data[1] == LINK_SELECTOR +#[must_use] +pub const fn is_link_response(data: &[u8]) -> bool { + matches!( + data, + [id, selector, ..] if *id == LINK_RESPONSE_REPORT && *selector == LINK_SELECTOR + ) } /// Queries the dongle once for the headset link state. Returns /// `Ok(Disconnected)` if no response arrives within the timeout window. +/// +/// # Errors +/// +/// Propagates I/O errors from writing the query or reading the response. pub fn link_status(hid: &mut Hidraw) -> io::Result<LinkState> { hid.write(&link_query_frame())?; - let deadline = Instant::now() + LINK_RESPONSE_TIMEOUT; + let deadline = Instant::now() + .checked_add(LINK_RESPONSE_TIMEOUT) + .unwrap_or_else(Instant::now); while let Some(remaining) = deadline.checked_duration_since(Instant::now()) { match hid.read_with_timeout(remaining)? { Some(data) if is_link_response(&data) => return Ok(LinkState::Connected), - Some(_) => continue, + Some(_) => {} None => break, } } @@ -93,9 +104,11 @@ pub fn link_status(hid: &mut Hidraw) -> io::Result<LinkState> { } /// Tracks link state across polls, debouncing disconnects and reporting -/// transitions. State starts unknown (`None`) and is pinned by the first -/// confirmed determination; `fire_initial` controls whether that first -/// determination is reported as a transition. +/// transitions. +/// +/// State starts unknown (`None`) and is pinned by the first confirmed +/// determination; `fire_initial` controls whether that first determination +/// is reported as a transition. #[derive(Debug)] pub struct StateTracker { state: Option<LinkState>, @@ -104,8 +117,10 @@ pub struct StateTracker { } impl StateTracker { - pub fn new(fire_initial: bool) -> StateTracker { - StateTracker { + /// Creates a tracker. See the struct docs for `fire_initial`. + #[must_use] + pub const fn new(fire_initial: bool) -> Self { + Self { state: None, misses: 0, fire_initial, @@ -113,22 +128,26 @@ impl StateTracker { } /// Current confirmed state, `None` until the first determination. - pub fn state(&self) -> Option<LinkState> { + #[must_use] + pub const fn state(&self) -> Option<LinkState> { self.state } /// Feed one poll result (`true` = link response seen) and get any /// confirmed transition. - pub fn update(&mut self, link_up: bool) -> Option<Transition> { + #[must_use] + pub const fn update(&mut self, link_up: bool) -> Option<Transition> { if link_up { self.misses = 0; - if self.state == Some(LinkState::Connected) { + if matches!(self.state, Some(LinkState::Connected)) { return None; } self.settle(LinkState::Connected) } else { - self.misses += 1; - if self.misses < LINK_DEBOUNCE_MISSES || self.state == Some(LinkState::Disconnected) { + self.misses = self.misses.saturating_add(1); + if self.misses < LINK_DEBOUNCE_MISSES + || matches!(self.state, Some(LinkState::Disconnected)) + { return None; } self.settle(LinkState::Disconnected) @@ -137,7 +156,7 @@ impl StateTracker { /// Pin the state, producing the transition unless it is the first /// determination and initial hooks are suppressed. - fn settle(&mut self, state: LinkState) -> Option<Transition> { + const fn settle(&mut self, state: LinkState) -> Option<Transition> { let initial = self.state.is_none(); self.state = Some(state); let transition = match state { |
