binary_layout/fields/primitive/
slice_access.rs

1use core::convert::TryFrom;
2
3use super::super::{Field, StorageIntoFieldView, StorageToFieldView};
4use super::PrimitiveField;
5use crate::endianness::Endianness;
6use crate::utils::data::Data;
7
8/// This trait is implemented for fields with "slice access",
9/// i.e. fields that are read/write directly without a copy
10/// by returning a borrowed slice to the underlying data.
11pub trait FieldSliceAccess<'a>: Field {
12    /// The type of slice returned from calls requesting read access
13    type SliceType: 'a;
14    /// The type of slice returned from calls requesting write access
15    type MutSliceType: 'a;
16
17    /// Borrow the data in the byte array with read access using the [Field] API.
18    ///
19    /// # Example:
20    /// ```
21    /// use binary_layout::prelude::*;
22    ///
23    /// binary_layout!(my_layout, LittleEndian, {
24    ///     //... other fields ...
25    ///     tail_data: [u8],
26    /// });
27    ///
28    /// fn func(storage_data: &[u8]) {
29    ///     let tail_data: &[u8] = my_layout::tail_data::data(storage_data);
30    /// }
31    /// ```
32    fn data(storage: &'a [u8]) -> Self::SliceType;
33
34    /// Borrow the data in the byte array with write access using the [Field] API.
35    ///
36    /// # Example:
37    /// ```
38    /// use binary_layout::prelude::*;
39    ///
40    /// binary_layout!(my_layout, LittleEndian, {
41    ///     //... other fields ...
42    ///     tail_data: [u8],
43    /// });
44    ///
45    /// fn func(storage_data: &mut [u8]) {
46    ///     let tail_data: &mut [u8] = my_layout::tail_data::data_mut(storage_data);
47    /// }
48    /// ```
49    fn data_mut(storage: &'a mut [u8]) -> Self::MutSliceType;
50}
51
52/// Field type `[u8]`:
53/// This field represents an [open ended byte array](crate#open-ended-byte-arrays-u8).
54/// In this impl, we define accessors for such fields.
55impl<'a, E: Endianness, const OFFSET_: usize> FieldSliceAccess<'a>
56    for PrimitiveField<[u8], E, OFFSET_>
57{
58    type SliceType = &'a [u8];
59    type MutSliceType = &'a mut [u8];
60
61    /// Borrow the data in the byte array with read access using the [Field] API.
62    ///
63    /// # Example:
64    /// ```
65    /// use binary_layout::prelude::*;
66    ///
67    /// binary_layout!(my_layout, LittleEndian, {
68    ///     //... other fields ...
69    ///     tail_data: [u8],
70    /// });
71    ///
72    /// fn func(storage_data: &[u8]) {
73    ///     let tail_data: &[u8] = my_layout::tail_data::data(storage_data);
74    /// }
75    /// ```
76    #[inline(always)]
77    fn data(storage: &'a [u8]) -> &'a [u8] {
78        &storage[Self::OFFSET..]
79    }
80
81    /// Borrow the data in the byte array with write access using the [Field] API.
82    ///
83    /// # Example:
84    /// ```
85    /// use binary_layout::prelude::*;
86    ///
87    /// binary_layout!(my_layout, LittleEndian, {
88    ///     //... other fields ...
89    ///     tail_data: [u8],
90    /// });
91    ///
92    /// fn func(storage_data: &mut [u8]) {
93    ///     let tail_data: &mut [u8] = my_layout::tail_data::data_mut(storage_data);
94    /// }
95    /// ```
96    #[inline(always)]
97    fn data_mut(storage: &'a mut [u8]) -> &'a mut [u8] {
98        &mut storage[Self::OFFSET..]
99    }
100}
101impl<E: Endianness, const OFFSET_: usize> Field for PrimitiveField<[u8], E, OFFSET_> {
102    /// See [Field::Endian]
103    type Endian = E;
104    /// See [Field::OFFSET]
105    const OFFSET: usize = OFFSET_;
106    /// See [Field::SIZE]
107    const SIZE: Option<usize> = None;
108}
109impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a [u8]>
110    for PrimitiveField<[u8], E, OFFSET_>
111{
112    type View = &'a [u8];
113
114    #[inline(always)]
115    fn view(storage: &'a [u8]) -> Self::View {
116        &storage[Self::OFFSET..]
117    }
118}
119
120impl<'a, E: Endianness, const OFFSET_: usize> StorageToFieldView<&'a mut [u8]>
121    for PrimitiveField<[u8], E, OFFSET_>
122{
123    type View = &'a mut [u8];
124
125    #[inline(always)]
126    fn view(storage: &'a mut [u8]) -> Self::View {
127        &mut storage[Self::OFFSET..]
128    }
129}
130
131impl<S: AsRef<[u8]>, E: Endianness, const OFFSET_: usize> StorageIntoFieldView<S>
132    for PrimitiveField<[u8], E, OFFSET_>
133{
134    type View = Data<S>;
135
136    #[inline(always)]
137    fn into_view(storage: S) -> Self::View {
138        Data::from(storage).into_subregion(Self::OFFSET..)
139    }
140}
141
142/// Field type `[u8; N]`:
143/// This field represents a [fixed size byte array](crate#fixed-size-byte-arrays-u8-n).
144/// In this impl, we define accessors for such fields.
145impl<'a, E: Endianness, const N: usize, const OFFSET_: usize> FieldSliceAccess<'a>
146    for PrimitiveField<[u8; N], E, OFFSET_>
147{
148    type SliceType = &'a [u8; N];
149    type MutSliceType = &'a mut [u8; N];
150
151    /// Borrow the data in the byte array with read access using the [Field] API.
152    /// See also [FieldSliceAccess::data].
153    ///
154    /// # Example:
155    /// ```
156    /// use binary_layout::prelude::*;
157    ///
158    /// binary_layout!(my_layout, LittleEndian, {
159    ///     //... other fields ...
160    ///     some_field: [u8; 5],
161    ///     //... other fields
162    /// });
163    ///
164    /// fn func(storage_data: &[u8]) {
165    ///     let some_field: &[u8; 5] = my_layout::some_field::data(storage_data);
166    /// }
167    /// ```
168    #[inline(always)]
169    fn data(storage: &'a [u8]) -> &'a [u8; N] {
170        <&[u8; N]>::try_from(&storage[Self::OFFSET..(Self::OFFSET + N)]).unwrap()
171    }
172
173    /// Borrow the data in the byte array with write access using the [Field] API.
174    /// See also [FieldSliceAccess::data_mut]
175    ///
176    /// # Example:
177    /// ```
178    /// use binary_layout::prelude::*;
179    ///
180    /// binary_layout!(my_layout, LittleEndian, {
181    ///     //... other fields ...
182    ///     some_field: [u8; 5],
183    ///     //... other fields
184    /// });
185    ///
186    /// fn func(storage_data: &mut [u8]) {
187    ///     let some_field: &mut [u8; 5] = my_layout::some_field::data_mut(storage_data);
188    /// }
189    /// ```
190    #[inline(always)]
191    fn data_mut(storage: &'a mut [u8]) -> &'a mut [u8; N] {
192        <&mut [u8; N]>::try_from(&mut storage[Self::OFFSET..(Self::OFFSET + N)]).unwrap()
193    }
194}
195impl<E: Endianness, const N: usize, const OFFSET_: usize> Field
196    for PrimitiveField<[u8; N], E, OFFSET_>
197{
198    /// See [Field::Endian]
199    type Endian = E;
200    /// See [Field::OFFSET]
201    const OFFSET: usize = OFFSET_;
202    /// See [Field::SIZE]
203    const SIZE: Option<usize> = Some(N);
204}
205impl<'a, E: Endianness, const N: usize, const OFFSET_: usize> StorageToFieldView<&'a [u8]>
206    for PrimitiveField<[u8; N], E, OFFSET_>
207{
208    type View = &'a [u8; N];
209
210    #[inline(always)]
211    fn view(storage: &'a [u8]) -> Self::View {
212        Self::View::try_from(&storage[Self::OFFSET..(Self::OFFSET + N)]).unwrap()
213    }
214}
215
216impl<'a, E: Endianness, const N: usize, const OFFSET_: usize> StorageToFieldView<&'a mut [u8]>
217    for PrimitiveField<[u8; N], E, OFFSET_>
218{
219    type View = &'a mut [u8; N];
220
221    #[inline(always)]
222    fn view(storage: &'a mut [u8]) -> Self::View {
223        Self::View::try_from(&mut storage[Self::OFFSET..(Self::OFFSET + N)]).unwrap()
224    }
225}
226
227impl<S: AsRef<[u8]>, E: Endianness, const N: usize, const OFFSET_: usize> StorageIntoFieldView<S>
228    for PrimitiveField<[u8; N], E, OFFSET_>
229{
230    type View = Data<S>;
231
232    #[inline(always)]
233    fn into_view(storage: S) -> Self::View {
234        Data::from(storage).into_subregion(Self::OFFSET..(Self::OFFSET + N))
235    }
236}
237
238#[cfg(test)]
239mod tests {
240    #![allow(clippy::float_cmp)]
241    use crate::prelude::*;
242    use crate::PrimitiveField;
243
244    #[test]
245    fn test_slice() {
246        let mut storage = [0; 1024];
247
248        type Field1 = PrimitiveField<[u8], LittleEndian, 5>;
249        type Field2 = PrimitiveField<[u8], BigEndian, 7>;
250        type Field3 = PrimitiveField<[u8], NativeEndian, 9>;
251
252        Field1::data_mut(&mut storage)[..5].copy_from_slice(&[10, 20, 30, 40, 50]);
253        Field2::data_mut(&mut storage)[..5].copy_from_slice(&[60, 70, 80, 90, 100]);
254        Field3::data_mut(&mut storage)[..5].copy_from_slice(&[110, 120, 130, 140, 150]);
255
256        assert_eq!(&[10, 20, 60, 70, 110], &Field1::data(&storage)[..5]);
257        assert_eq!(&[60, 70, 110, 120, 130], &Field2::data(&storage)[..5]);
258        assert_eq!(&[110, 120, 130, 140, 150], &Field3::data(&storage)[..5]);
259
260        // Check types are correct
261        let _a: &[u8] = Field1::data(&storage);
262        let _b: &mut [u8] = Field1::data_mut(&mut storage);
263    }
264
265    #[test]
266    fn test_array() {
267        let mut storage = [0; 1024];
268
269        type Field1 = PrimitiveField<[u8; 2], LittleEndian, 5>;
270        type Field2 = PrimitiveField<[u8; 5], BigEndian, 6>;
271        type Field3 = PrimitiveField<[u8; 5], NativeEndian, 7>;
272
273        Field1::data_mut(&mut storage).copy_from_slice(&[10, 20]);
274        Field2::data_mut(&mut storage).copy_from_slice(&[60, 70, 80, 90, 100]);
275        Field3::data_mut(&mut storage).copy_from_slice(&[60, 70, 80, 90, 100]);
276
277        assert_eq!(&[10, 60], Field1::data(&storage));
278        assert_eq!(&[60, 60, 70, 80, 90], Field2::data(&storage));
279        assert_eq!(&[60, 70, 80, 90, 100], Field3::data(&storage));
280
281        assert_eq!(Some(2), PrimitiveField::<[u8; 2], LittleEndian, 5>::SIZE);
282        assert_eq!(Some(5), PrimitiveField::<[u8; 5], BigEndian, 5>::SIZE);
283        assert_eq!(Some(5), PrimitiveField::<[u8; 5], NativeEndian, 5>::SIZE);
284
285        // Check types are correct
286        let _a: &[u8; 2] = Field1::data(&storage);
287        let _b: &mut [u8; 2] = Field1::data_mut(&mut storage);
288    }
289}