1#![warn(clippy::pedantic)]
5#![allow(clippy::too_many_lines)]
7#![allow(clippy::must_use_candidate)]
9#![allow(
10 clippy::missing_errors_doc,
11 clippy::range_plus_one,
12 clippy::type_complexity,
13 clippy::doc_markdown
14)]
15#![deny(unconditional_recursion)]
16#![allow(dead_code)]
17#![cfg_attr(not(feature = "std"), no_std)]
18
19#[cfg(feature = "std")]
20#[macro_use]
21extern crate std;
22
23#[cfg_attr(not(feature = "std"), macro_use)]
24extern crate alloc;
25pub(crate) use futures_util::stream::Stream;
26pub type BoxFuture<'a, T> = core::pin::Pin<Box<dyn core::future::Future<Output = T> + 'a>>;
28pub type BoxStream<'a, T> = core::pin::Pin<Box<dyn Stream<Item = T> + 'a>>;
30extern crate core;
31pub mod bytes;
32pub mod channel;
33#[cfg(feature = "classic")]
34pub mod classic;
35pub mod error;
36#[cfg(feature = "hci")]
37pub mod hci;
38pub mod le;
39pub mod uri;
40pub mod uuid;
41#[cfg(feature = "winrt_drives")]
42pub mod windows;
43
44use core::convert::{TryFrom, TryInto};
45
46#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
49pub enum PackError {
50 BadOpcode,
51 BadLength { expected: usize, got: usize },
52 BadBytes { index: Option<usize> },
53 InvalidFields,
54}
55impl PackError {
56 #[inline]
59 pub fn expect_length(expected: usize, buf: &[u8]) -> Result<(), PackError> {
60 if buf.len() == expected {
61 Ok(())
62 } else {
63 Err(PackError::BadLength {
64 expected,
65 got: buf.len(),
66 })
67 }
68 }
69 #[inline]
72 pub fn atleast_length(expected: usize, buf: &[u8]) -> Result<(), PackError> {
73 if buf.len() == expected {
74 Ok(())
75 } else {
76 Err(PackError::BadLength {
77 expected,
78 got: buf.len(),
79 })
80 }
81 }
82 #[inline]
84 pub fn bad_index(index: usize) -> PackError {
85 PackError::BadBytes { index: Some(index) }
86 }
87}
88impl crate::error::Error for PackError {}
89
90#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
93pub struct ConversionError(pub ());
94#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)]
97pub struct RSSI(i8);
98impl RSSI {
99 pub const MIN_RSSI_I8: i8 = -127;
100 pub const MAX_RSSI_I8: i8 = 20;
101 pub const MAX_RSSI: RSSI = RSSI(Self::MAX_RSSI_I8);
102 pub const MIN_RSSI: RSSI = RSSI(Self::MIN_RSSI_I8);
103 pub fn new(dbm: i8) -> RSSI {
107 assert!(
108 dbm >= Self::MIN_RSSI_I8 && dbm <= Self::MAX_RSSI_I8,
109 "invalid rssi '{}'",
110 dbm
111 );
112 RSSI(dbm)
113 }
114 pub const UNSUPPORTED_RSSI: i8 = 127;
115 pub fn maybe_rssi(val: i8) -> Result<Option<RSSI>, ConversionError> {
116 match val {
117 -127..=20 => Ok(Some(RSSI(val))),
118 127 => Ok(None),
119 _ => Err(ConversionError(())),
120 }
121 }
122}
123impl From<RSSI> for i8 {
124 fn from(rssi: RSSI) -> Self {
125 rssi.0
126 }
127}
128
129impl From<RSSI> for u8 {
130 fn from(rssi: RSSI) -> Self {
131 rssi.0 as u8
132 }
133}
134impl TryFrom<i8> for RSSI {
135 type Error = ConversionError;
136
137 fn try_from(value: i8) -> Result<Self, Self::Error> {
138 if value > Self::MAX_RSSI_I8 || value < Self::MIN_RSSI_I8 {
139 Err(ConversionError(()))
140 } else {
141 Ok(RSSI(value))
142 }
143 }
144}
145impl TryFrom<u8> for RSSI {
146 type Error = ConversionError;
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 (value as i8).try_into()
150 }
151}
152#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
157pub struct MilliDBM(pub i32);
158impl MilliDBM {
159 pub fn new(milli_dbm: i32) -> MilliDBM {
160 MilliDBM(milli_dbm)
161 }
162}
163pub const BT_ADDRESS_LEN: usize = 6;
165
166#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
168pub struct BTAddress(pub [u8; BT_ADDRESS_LEN]);
169impl BTAddress {
170 pub const LEN: usize = BT_ADDRESS_LEN;
171 pub const ZEROED: BTAddress = BTAddress([0_u8; 6]);
172 pub fn new(bytes: &[u8]) -> BTAddress {
176 assert_eq!(bytes.len(), BT_ADDRESS_LEN, "address wrong length");
177 BTAddress(bytes.try_into().expect("length checked by assert_eq above"))
178 }
179 pub fn unpack_from(bytes: &[u8]) -> Result<Self, PackError> {
180 PackError::expect_length(BT_ADDRESS_LEN, bytes)?;
181 Ok(Self::new(bytes))
182 }
183 pub fn pack_into(self, bytes: &mut [u8]) -> Result<(), PackError> {
184 PackError::expect_length(BT_ADDRESS_LEN, bytes)?;
185 bytes.copy_from_slice(&self.0[..]);
186 Ok(())
187 }
188 pub fn address_type(self) -> AddressType {
189 let address_type_bits = (self.0[BT_ADDRESS_LEN - 1] & 0xC0) >> 6;
190 match address_type_bits {
191 0b00 => AddressType::NonResolvablePrivate,
192 0b01 => AddressType::ResolvablePrivateAddress,
193 0b11 => AddressType::StaticDevice,
194 _ => AddressType::RFU,
196 }
197 }
198 pub fn private_address_parts(self) -> Option<(u32, u32)> {
201 match self.address_type() {
202 AddressType::ResolvablePrivateAddress => Some((
203 u32::from_le_bytes([self.0[0], self.0[1], self.0[2], 0]),
204 u32::from_le_bytes([self.0[3], self.0[4], self.0[5], 0]),
205 )),
206 _ => None,
207 }
208 }
209}
210#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Debug, Hash)]
211pub enum AddressType {
212 NonResolvablePrivate = 0b00,
213 ResolvablePrivateAddress = 0b01,
214 RFU = 0b10,
215 StaticDevice = 0b11,
216}
217#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
220#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
221pub struct CompanyID(pub u16);
222impl CompanyID {
223 pub const fn byte_len() -> usize {
225 2
226 }
227}
228impl crate::bytes::ToFromBytesEndian for CompanyID {
229 type AsBytesType = [u8; 2];
230
231 #[must_use]
232 fn to_bytes_le(&self) -> Self::AsBytesType {
233 (self.0).to_bytes_le()
234 }
235
236 #[must_use]
237 fn to_bytes_be(&self) -> Self::AsBytesType {
238 (self.0).to_bytes_be()
239 }
240
241 #[must_use]
242 fn from_bytes_le(bytes: &[u8]) -> Option<Self> {
243 Some(CompanyID(u16::from_bytes_le(bytes)?))
244 }
245
246 #[must_use]
247 fn from_bytes_be(bytes: &[u8]) -> Option<Self> {
248 Some(CompanyID(u16::from_bytes_be(bytes)?))
249 }
250}