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