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