trouble_host/types/
gatt_traits.rs1use core::{mem, slice};
2
3use bt_hci::uuid::BluetoothUuid16;
4use heapless::{String, Vec};
5
6#[derive(Debug, PartialEq, Eq, Clone, Copy)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub enum FromGattError {
10 InvalidLength,
12 InvalidCharacter,
14}
15
16#[allow(private_bounds)]
18pub trait FixedGattValue: FromGatt {
19 const SIZE: usize;
21
22 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError>;
25
26 fn as_gatt(&self) -> &[u8];
29}
30
31pub trait AsGatt: Sized {
33 const MIN_SIZE: usize;
35 const MAX_SIZE: usize;
37 fn as_gatt(&self) -> &[u8];
40}
41
42pub trait FromGatt: AsGatt {
46 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError>;
49}
50
51impl<T: FixedGattValue> FromGatt for T {
52 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
53 <Self as FixedGattValue>::from_gatt(data)
54 }
55}
56
57impl<T: FixedGattValue> AsGatt for T {
58 const MIN_SIZE: usize = Self::SIZE;
59 const MAX_SIZE: usize = Self::SIZE;
60
61 fn as_gatt(&self) -> &[u8] {
62 <Self as FixedGattValue>::as_gatt(self)
63 }
64}
65
66trait Primitive: Copy {}
67impl Primitive for u8 {}
68impl Primitive for u16 {}
69impl Primitive for u32 {}
70impl Primitive for u64 {}
71impl Primitive for i8 {}
72impl Primitive for i16 {}
73impl Primitive for i32 {}
74impl Primitive for i64 {}
75impl Primitive for f32 {}
76impl Primitive for f64 {}
77impl Primitive for BluetoothUuid16 {} impl<T: Primitive> FixedGattValue for T {
80 const SIZE: usize = mem::size_of::<Self>();
81
82 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
83 if data.len() != Self::SIZE {
84 Err(FromGattError::InvalidLength)
85 } else {
86 unsafe { Ok((data.as_ptr() as *const Self).read_unaligned()) }
91 }
92 }
93
94 fn as_gatt(&self) -> &[u8] {
95 unsafe { slice::from_raw_parts(self as *const Self as *const u8, Self::SIZE) }
99 }
100}
101
102impl FixedGattValue for bool {
103 const SIZE: usize = 1;
104
105 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
106 if data.len() != Self::SIZE {
107 Err(FromGattError::InvalidLength)
108 } else {
109 Ok(data != [0x00])
110 }
111 }
112
113 fn as_gatt(&self) -> &[u8] {
114 match self {
115 true => &[0x01],
116 false => &[0x00],
117 }
118 }
119}
120
121impl<const N: usize> FromGatt for Vec<u8, N> {
122 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
123 Self::from_slice(data).map_err(|_| FromGattError::InvalidLength)
124 }
125}
126
127impl<const N: usize> AsGatt for Vec<u8, N> {
128 const MIN_SIZE: usize = 0;
129 const MAX_SIZE: usize = N;
130
131 fn as_gatt(&self) -> &[u8] {
132 self
133 }
134}
135
136impl<const N: usize> FromGatt for [u8; N] {
137 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
138 if data.len() <= Self::MAX_SIZE {
139 let mut actual = [0; N];
140 actual[..data.len()].copy_from_slice(data);
141 Ok(actual)
142 } else {
143 data.try_into().map_err(|_| FromGattError::InvalidLength)
144 }
145 }
146}
147
148impl<const N: usize> AsGatt for [u8; N] {
149 const MIN_SIZE: usize = 0;
150 const MAX_SIZE: usize = N;
151
152 fn as_gatt(&self) -> &[u8] {
153 self.as_slice()
154 }
155}
156
157impl<const N: usize> FromGatt for String<N> {
158 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
159 String::from_utf8(unwrap!(Vec::from_slice(data).map_err(|_| FromGattError::InvalidLength)))
160 .map_err(|_| FromGattError::InvalidCharacter)
161 }
162}
163
164impl<const N: usize> AsGatt for String<N> {
165 const MIN_SIZE: usize = 0;
166 const MAX_SIZE: usize = N;
167
168 fn as_gatt(&self) -> &[u8] {
169 self.as_ref()
170 }
171}
172
173impl AsGatt for &'static str {
174 const MIN_SIZE: usize = 0;
175 const MAX_SIZE: usize = usize::MAX;
176
177 fn as_gatt(&self) -> &[u8] {
178 self.as_bytes()
179 }
180}
181
182impl AsGatt for &'static [u8] {
183 const MIN_SIZE: usize = 0;
184 const MAX_SIZE: usize = usize::MAX;
185
186 fn as_gatt(&self) -> &[u8] {
187 self
188 }
189}
190
191impl AsGatt for crate::types::uuid::Uuid {
192 const MIN_SIZE: usize = 2;
193 const MAX_SIZE: usize = 16;
194
195 fn as_gatt(&self) -> &[u8] {
196 self.as_raw()
197 }
198}
199
200impl FromGatt for crate::types::uuid::Uuid {
201 fn from_gatt(data: &[u8]) -> Result<Self, FromGattError> {
202 Self::try_from(data).map_err(|_| FromGattError::InvalidLength)
203 }
204}