umsh_ulcp/
ble.rs

1//! The Bluetooth link enumeration (`PROP_BLE_LINK`).
2//!
3//! The property value is a single octet naming how far the device's
4//! Bluetooth transport has got with whoever is on the other end of it.
5//! Being connected and being attached are different claims: a central can
6//! hold the device's one peripheral slot without ever opening a ULCP
7//! session on it, and telling those apart is the difference between "a
8//! host is talking to this device" and "something is sitting on its
9//! Bluetooth".
10
11/// `PROP_BLE_LINK` states.
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub enum BleLinkState {
14    /// `BLE_LINK_NONE` — nothing is connected over Bluetooth.
15    #[default]
16    None = 0,
17    /// `BLE_LINK_CONNECTED` — a central holds a connection but has not
18    /// opened a ULCP session on it.
19    Connected = 1,
20    /// `BLE_LINK_ATTACHED` — a host is attached and running ULCP over
21    /// Bluetooth.
22    Attached = 2,
23}
24
25impl BleLinkState {
26    /// The wire code for this state.
27    pub const fn code(self) -> u8 {
28        self as u8
29    }
30
31    /// Strict conversion from a wire octet.
32    pub const fn from_code(code: u8) -> Option<Self> {
33        match code {
34            0 => Some(Self::None),
35            1 => Some(Self::Connected),
36            2 => Some(Self::Attached),
37            _ => None,
38        }
39    }
40
41    /// Whether anything at all holds a Bluetooth connection to the
42    /// device, attached or not.
43    pub const fn is_connected(self) -> bool {
44        !matches!(self, Self::None)
45    }
46
47    /// Whether a host is attached over Bluetooth, which is the question
48    /// "is someone managing this device right now" actually asks.
49    pub const fn is_attached(self) -> bool {
50        matches!(self, Self::Attached)
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn codes_round_trip_strictly() {
60        assert_eq!(BleLinkState::from_code(0), Some(BleLinkState::None));
61        assert_eq!(BleLinkState::from_code(1), Some(BleLinkState::Connected));
62        assert_eq!(BleLinkState::from_code(2), Some(BleLinkState::Attached));
63        assert_eq!(BleLinkState::from_code(3), None);
64        assert_eq!(BleLinkState::None.code(), 0);
65        assert_eq!(BleLinkState::Connected.code(), 1);
66        assert_eq!(BleLinkState::Attached.code(), 2);
67    }
68
69    #[test]
70    fn connected_and_attached_are_different_claims() {
71        assert_eq!(BleLinkState::default(), BleLinkState::None);
72        assert!(!BleLinkState::None.is_connected());
73        assert!(BleLinkState::Connected.is_connected());
74        assert!(!BleLinkState::Connected.is_attached());
75        assert!(BleLinkState::Attached.is_connected());
76        assert!(BleLinkState::Attached.is_attached());
77    }
78}