1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! A no_std friendly array wrapper to expose a variable length prefix of the array.
16 #![no_std]
17 
18 #[cfg(feature = "std")]
19 extern crate std;
20 
21 use core::{borrow, fmt};
22 
23 /// A view into the first `len` elements of an array.
24 ///
25 /// Useful when you have a fixed size array but variable length data that fits in it.
26 #[derive(PartialEq, Eq, Clone)]
27 pub struct ArrayView<T, const N: usize> {
28     array: [T; N],
29     len: usize,
30 }
31 
32 // manual impl to avoid showing parts of the buffer beyond len
33 impl<T: fmt::Debug, const N: usize> fmt::Debug for ArrayView<T, N> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result34     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35         self.as_slice().fmt(f)
36     }
37 }
38 
39 impl<T, const N: usize> ArrayView<T, N> {
40     /// Destructures this ArrayView into a (length, payload) pair.
into_raw_parts(self) -> (usize, [T; N])41     pub fn into_raw_parts(self) -> (usize, [T; N]) {
42         (self.len, self.array)
43     }
44     /// A version of [`ArrayView#try_from_array`] which panics if `len > buffer.len()`,
45     /// suitable for usage in `const` contexts.
const_from_array(array: [T; N], len: usize) -> ArrayView<T, N>46     pub const fn const_from_array(array: [T; N], len: usize) -> ArrayView<T, N> {
47         if N < len {
48             panic!("Invalid const ArrayView");
49         } else {
50             ArrayView { array, len }
51         }
52     }
53 
54     /// Create an [ArrayView] of the first `len` elements of `buffer`.
55     ///
56     /// Returns `None` if `len > buffer.len()`.
try_from_array(array: [T; N], len: usize) -> Option<ArrayView<T, N>>57     pub fn try_from_array(array: [T; N], len: usize) -> Option<ArrayView<T, N>> {
58         if N < len {
59             None
60         } else {
61             Some(ArrayView { array, len })
62         }
63     }
64 
65     /// Returns the occupied portion of the array as a slice.
as_slice(&self) -> &[T]66     pub fn as_slice(&self) -> &[T] {
67         &self.array[..self.len]
68     }
69 
70     /// The length of the data in the view
len(&self) -> usize71     pub fn len(&self) -> usize {
72         self.len
73     }
74 
75     /// Returns true if the length is 0
is_empty(&self) -> bool76     pub fn is_empty(&self) -> bool {
77         self.len == 0
78     }
79 }
80 
81 impl<T: Default + Copy, const N: usize> ArrayView<T, N> {
82     /// Create an `ArrayView` containing the data from the provided slice, assuming the slice can
83     /// fit in the array size.
try_from_slice(slice: &[T]) -> Option<ArrayView<T, N>>84     pub fn try_from_slice(slice: &[T]) -> Option<ArrayView<T, N>> {
85         if N < slice.len() {
86             None
87         } else {
88             let mut array = [T::default(); N];
89             array[..slice.len()].copy_from_slice(slice);
90             Some(ArrayView { array, len: slice.len() })
91         }
92     }
93 }
94 
95 impl<T, const N: usize> AsRef<[T]> for ArrayView<T, N> {
as_ref(&self) -> &[T]96     fn as_ref(&self) -> &[T] {
97         self.as_slice()
98     }
99 }
100 
101 impl<T, const N: usize> borrow::Borrow<[T]> for ArrayView<T, N> {
borrow(&self) -> &[T]102     fn borrow(&self) -> &[T] {
103         self.as_slice()
104     }
105 }
106 
107 #[cfg(test)]
108 #[allow(clippy::unwrap_used)]
109 mod tests {
110     extern crate std;
111     use crate::ArrayView;
112     use std::format;
113 
114     #[test]
debug_only_shows_len_elements()115     fn debug_only_shows_len_elements() {
116         assert_eq!(
117             "[1, 2]",
118             &format!("{:?}", ArrayView::try_from_array([1, 2, 3, 4, 5], 2).unwrap())
119         );
120     }
121 
122     #[test]
try_from_slice_too_long()123     fn try_from_slice_too_long() {
124         assert_eq!(None, ArrayView::<u8, 3>::try_from_slice(&[1, 2, 3, 4, 5]));
125     }
126 
127     #[test]
try_from_slice_ok()128     fn try_from_slice_ok() {
129         let view = ArrayView::<u8, 10>::try_from_slice(&[1, 2, 3, 4, 5]).unwrap();
130         assert_eq!(&[1, 2, 3, 4, 5], view.as_slice())
131     }
132 }
133