grafton_visca/command/bytes/
mod.rs1pub mod builder;
7pub mod constants;
8
9pub use builder::ConstCommandBuilder;
10
11pub const VISCA_TERMINATOR: u8 = 0xFF;
13
14pub const DEFAULT_CAMERA_ID: u8 = 0x81;
16
17#[derive(Debug, Clone, Copy)]
54pub struct FixedCommandBytes<const N: usize> {
55 bytes: [u8; N],
56 len: usize,
57}
58
59impl<const N: usize> FixedCommandBytes<N> {
60 #[inline]
67 pub(crate) const fn new(bytes: [u8; N], len: usize) -> Self {
68 debug_assert!(len <= N);
69 Self { bytes, len }
70 }
71
72 #[inline]
77 pub const fn as_slice(&self) -> &[u8] {
78 self.bytes.split_at(self.len).0
82 }
83
84 #[inline]
86 pub const fn len(&self) -> usize {
87 self.len
88 }
89
90 #[inline]
92 pub const fn is_empty(&self) -> bool {
93 self.len == 0
94 }
95
96 #[inline]
101 pub const fn into_array(self) -> [u8; N] {
102 self.bytes
103 }
104
105 #[inline]
110 pub const fn as_array(&self) -> &[u8; N] {
111 &self.bytes
112 }
113}
114
115impl<const N: usize> AsRef<[u8]> for FixedCommandBytes<N> {
116 #[inline]
117 fn as_ref(&self) -> &[u8] {
118 &self.bytes[..self.len]
119 }
120}
121
122impl<const N: usize> core::ops::Deref for FixedCommandBytes<N> {
123 type Target = [u8];
124
125 #[inline]
126 fn deref(&self) -> &Self::Target {
127 &self.bytes[..self.len]
128 }
129}
130
131impl<const N: usize> PartialEq for FixedCommandBytes<N> {
133 #[inline]
134 fn eq(&self, other: &Self) -> bool {
135 self.as_slice() == other.as_slice()
136 }
137}
138
139impl<const N: usize> Eq for FixedCommandBytes<N> {}
140
141impl<const N: usize> PartialEq<[u8]> for FixedCommandBytes<N> {
143 #[inline]
144 fn eq(&self, other: &[u8]) -> bool {
145 self.as_slice() == other
146 }
147}
148
149impl<const N: usize> PartialEq<&[u8]> for FixedCommandBytes<N> {
150 #[inline]
151 fn eq(&self, other: &&[u8]) -> bool {
152 self.as_slice() == *other
153 }
154}
155
156impl<const N: usize> core::hash::Hash for FixedCommandBytes<N> {
158 #[inline]
159 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
160 self.as_slice().hash(state);
161 }
162}
163
164impl<const N: usize> core::borrow::Borrow<[u8]> for FixedCommandBytes<N> {
166 #[inline]
167 fn borrow(&self) -> &[u8] {
168 self.as_slice()
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn test_fixed_command_bytes_as_slice() {
178 let bytes = [0x81, 0x01, 0x04, 0x47, VISCA_TERMINATOR, 0x00, 0x00, 0x00];
179 let fixed = FixedCommandBytes::new(bytes, 5);
180
181 assert_eq!(
182 fixed.as_slice(),
183 &[0x81, 0x01, 0x04, 0x47, VISCA_TERMINATOR]
184 );
185 assert_eq!(fixed.len(), 5);
186 assert!(!fixed.is_empty());
187 }
188
189 #[test]
190 fn test_fixed_command_bytes_as_ref() {
191 let bytes = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
192 let fixed = FixedCommandBytes::new(bytes, 3);
193
194 let slice: &[u8] = fixed.as_ref();
195 assert_eq!(slice, &[0x81, 0x01, VISCA_TERMINATOR]);
196 }
197
198 #[test]
199 fn test_fixed_command_bytes_deref() {
200 let bytes = [0x81, VISCA_TERMINATOR, 0x00, 0x00];
201 let fixed = FixedCommandBytes::new(bytes, 2);
202
203 assert_eq!(&*fixed, &[0x81, VISCA_TERMINATOR]);
205 assert_eq!(fixed.last(), Some(&VISCA_TERMINATOR));
206 }
207
208 #[test]
209 fn test_fixed_command_bytes_into_array() {
210 let bytes = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
211 let fixed = FixedCommandBytes::new(bytes, 3);
212
213 let array = fixed.into_array();
214 assert_eq!(array, [0x81, 0x01, VISCA_TERMINATOR, 0x00]);
215 }
216
217 #[test]
218 fn test_fixed_command_bytes_as_array() {
219 let bytes = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
220 let fixed = FixedCommandBytes::new(bytes, 3);
221
222 assert_eq!(fixed.as_array(), &[0x81, 0x01, VISCA_TERMINATOR, 0x00]);
223 }
224
225 #[test]
226 fn test_fixed_command_bytes_terminates_correctly() {
227 let bytes = [0x81, 0x01, 0x04, 0x47, VISCA_TERMINATOR, 0x00, 0x00, 0x00];
228 let fixed = FixedCommandBytes::new(bytes, 5);
229
230 assert_eq!(fixed.as_slice().last(), Some(&VISCA_TERMINATOR));
232
233 assert!(!fixed.as_slice().contains(&0x00) || fixed.as_slice()[0..4].contains(&0x00));
235 }
236
237 #[test]
238 fn test_fixed_command_bytes_equality_ignores_trailing_bytes() {
239 let bytes1 = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
241 let bytes2 = [0x81, 0x01, VISCA_TERMINATOR, 0xAB]; let fixed1 = FixedCommandBytes::new(bytes1, 3);
244 let fixed2 = FixedCommandBytes::new(bytes2, 3);
245
246 assert_eq!(fixed1, fixed2);
248 }
249
250 #[test]
251 fn test_fixed_command_bytes_partial_eq_with_slice() {
252 let bytes = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
253 let fixed = FixedCommandBytes::new(bytes, 3);
254
255 assert!(*fixed == [0x81, 0x01, VISCA_TERMINATOR]);
257 assert!(fixed.as_slice() == [0x81, 0x01, VISCA_TERMINATOR]);
258
259 assert!(*fixed != [0x81, 0x01, 0x00]);
261 }
262
263 #[test]
264 fn test_fixed_command_bytes_hash_consistency() {
265 use core::hash::{Hash, Hasher};
266
267 let bytes1 = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
269 let bytes2 = [0x81, 0x01, VISCA_TERMINATOR, 0xAB]; let fixed1 = FixedCommandBytes::new(bytes1, 3);
272 let fixed2 = FixedCommandBytes::new(bytes2, 3);
273
274 fn hash_it<H: Hash>(val: &H) -> u64 {
276 let mut hasher = std::collections::hash_map::DefaultHasher::new();
277 val.hash(&mut hasher);
278 hasher.finish()
279 }
280
281 assert_eq!(hash_it(&fixed1), hash_it(&fixed2));
282 }
283
284 #[test]
285 fn test_fixed_command_bytes_borrow() {
286 use core::borrow::Borrow;
287
288 let bytes = [0x81, 0x01, VISCA_TERMINATOR, 0x00];
289 let fixed = FixedCommandBytes::new(bytes, 3);
290
291 let slice: &[u8] = fixed.borrow();
293 assert_eq!(slice, &[0x81, 0x01, VISCA_TERMINATOR]);
294 }
295}