ctaphid_types/
channel.rs

1// Copyright (C) 2021-2022 Robin Krahl <robin.krahl@ireas.org>
2// SPDX-License-Identifier: Apache-2.0 or MIT
3
4use core::fmt;
5
6/// A CTAPHID channel.
7///
8/// See [ยง 11.2.3 of the CTAP specification][spec].
9///
10/// [spec]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#usb-channels
11#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
12pub struct Channel(u32);
13
14impl Channel {
15    /// The broadcast channel (`0xffff_ffff`).
16    pub const BROADCAST: Channel = Channel(0xffff_ffff);
17
18    /// Encodes the channel as a byte array.
19    pub fn to_bytes(self) -> [u8; 4] {
20        self.into()
21    }
22}
23
24impl From<u32> for Channel {
25    fn from(id: u32) -> Self {
26        Self(id)
27    }
28}
29
30impl From<Channel> for u32 {
31    fn from(channel: Channel) -> u32 {
32        channel.0
33    }
34}
35
36impl From<[u8; 4]> for Channel {
37    fn from(data: [u8; 4]) -> Self {
38        Self::from(u32::from_be_bytes(data))
39    }
40}
41
42impl From<&[u8; 4]> for Channel {
43    fn from(data: &[u8; 4]) -> Self {
44        Self::from(*data)
45    }
46}
47
48impl From<Channel> for [u8; 4] {
49    fn from(channel: Channel) -> Self {
50        channel.0.to_be_bytes()
51    }
52}
53
54impl fmt::Display for Channel {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        write!(f, "0x{:x}", self.0)
57    }
58}
59
60#[cfg(test)]
61mod test {
62    use super::Channel;
63
64    impl quickcheck::Arbitrary for Channel {
65        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
66            Self(u32::arbitrary(g))
67        }
68
69        fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
70            Box::new(self.0.shrink().map(Self))
71        }
72    }
73
74    quickcheck::quickcheck! {
75        fn from_u32(value: u32) -> bool {
76            u32::from(Channel::from(value)) == value
77        }
78    }
79}