• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #![forbid(unsafe_code)]
18 #![deny(
19     missing_docs,
20     clippy::indexing_slicing,
21     clippy::unwrap_used,
22     clippy::panic,
23     clippy::expect_used
24 )]
25 
26 use core::{borrow, fmt};
27 
28 /// A view into the first `len` elements of an array.
29 ///
30 /// Useful when you have a fixed size array but variable length data that fits in it.
31 #[derive(PartialEq, Eq, Clone)]
32 pub struct ArrayView<T, const N: usize> {
33     array: [T; N],
34     len: usize,
35 }
36 
37 // manual impl to avoid showing parts of the buffer beyond len
38 impl<T: fmt::Debug, const N: usize> fmt::Debug for ArrayView<T, N> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result39     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40         self.as_slice().fmt(f)
41     }
42 }
43 
44 impl<T, const N: usize> ArrayView<T, N> {
45     /// Create an [ArrayView] of the first `len` elements of `buffer`.
46     ///
47     /// Returns `None` if `len > buffer.len()`.
try_from_array(array: [T; N], len: usize) -> Option<ArrayView<T, N>>48     pub fn try_from_array(array: [T; N], len: usize) -> Option<ArrayView<T, N>> {
49         if N < len {
50             None
51         } else {
52             Some(ArrayView { array, len })
53         }
54     }
55 
56     /// Returns the prefix of the array as a slice.
as_slice(&self) -> &[T]57     pub fn as_slice(&self) -> &[T] {
58         &self.array[..self.len]
59     }
60 
61     /// The length of the data in the view
len(&self) -> usize62     pub fn len(&self) -> usize {
63         self.len
64     }
65 
66     /// Returns true if the length is 0
is_empty(&self) -> bool67     pub fn is_empty(&self) -> bool {
68         self.len == 0
69     }
70 }
71 
72 impl<T: Default + Copy, const N: usize> ArrayView<T, N> {
73     /// Create an `ArrayView` containing the data from the provided slice, assuming the slice can
74     /// fit in the array size.
try_from_slice(slice: &[T]) -> Option<ArrayView<T, N>>75     pub fn try_from_slice(slice: &[T]) -> Option<ArrayView<T, N>> {
76         if N < slice.len() {
77             None
78         } else {
79             let mut array = [T::default(); N];
80             array[..slice.len()].copy_from_slice(slice);
81             Some(ArrayView {
82                 array,
83                 len: slice.len(),
84             })
85         }
86     }
87 }
88 
89 impl<T, const N: usize> AsRef<[T]> for ArrayView<T, N> {
as_ref(&self) -> &[T]90     fn as_ref(&self) -> &[T] {
91         self.as_slice()
92     }
93 }
94 
95 impl<T, const N: usize> borrow::Borrow<[T]> for ArrayView<T, N> {
borrow(&self) -> &[T]96     fn borrow(&self) -> &[T] {
97         self.as_slice()
98     }
99 }
100 
101 #[cfg(test)]
102 mod tests {
103     #![allow(clippy::unwrap_used)]
104 
105     extern crate std;
106     use crate::ArrayView;
107     use std::format;
108 
109     #[test]
debug_only_shows_len_elements()110     fn debug_only_shows_len_elements() {
111         assert_eq!(
112             "[1, 2]",
113             &format!(
114                 "{:?}",
115                 ArrayView::try_from_array([1, 2, 3, 4, 5], 2).unwrap()
116             )
117         );
118     }
119 
120     #[test]
try_from_slice_too_long()121     fn try_from_slice_too_long() {
122         assert_eq!(None, ArrayView::<u8, 3>::try_from_slice(&[1, 2, 3, 4, 5]));
123     }
124 
125     #[test]
try_from_slice_ok()126     fn try_from_slice_ok() {
127         let view = ArrayView::<u8, 10>::try_from_slice(&[1, 2, 3, 4, 5]).unwrap();
128         assert_eq!(&[1, 2, 3, 4, 5], view.as_slice())
129     }
130 }
131