// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! A no_std friendly array wrapper to expose a variable length prefix of the array. #![no_std] #[cfg(feature = "std")] extern crate std; use core::{borrow, fmt}; /// A view into the first `len` elements of an array. /// /// Useful when you have a fixed size array but variable length data that fits in it. #[derive(PartialEq, Eq, Clone)] pub struct ArrayView { array: [T; N], len: usize, } // manual impl to avoid showing parts of the buffer beyond len impl fmt::Debug for ArrayView { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_slice().fmt(f) } } impl ArrayView { /// Destructures this ArrayView into a (length, payload) pair. pub fn into_raw_parts(self) -> (usize, [T; N]) { (self.len, self.array) } /// A version of [`ArrayView#try_from_array`] which panics if `len > buffer.len()`, /// suitable for usage in `const` contexts. pub const fn const_from_array(array: [T; N], len: usize) -> ArrayView { if N < len { panic!("Invalid const ArrayView"); } else { ArrayView { array, len } } } /// Create an [ArrayView] of the first `len` elements of `buffer`. /// /// Returns `None` if `len > buffer.len()`. pub fn try_from_array(array: [T; N], len: usize) -> Option> { if N < len { None } else { Some(ArrayView { array, len }) } } /// Returns the occupied portion of the array as a slice. pub fn as_slice(&self) -> &[T] { &self.array[..self.len] } /// The length of the data in the view pub fn len(&self) -> usize { self.len } /// Returns true if the length is 0 pub fn is_empty(&self) -> bool { self.len == 0 } } impl ArrayView { /// Create an `ArrayView` containing the data from the provided slice, assuming the slice can /// fit in the array size. pub fn try_from_slice(slice: &[T]) -> Option> { if N < slice.len() { None } else { let mut array = [T::default(); N]; array[..slice.len()].copy_from_slice(slice); Some(ArrayView { array, len: slice.len() }) } } } impl AsRef<[T]> for ArrayView { fn as_ref(&self) -> &[T] { self.as_slice() } } impl borrow::Borrow<[T]> for ArrayView { fn borrow(&self) -> &[T] { self.as_slice() } } #[cfg(test)] #[allow(clippy::unwrap_used)] mod tests { extern crate std; use crate::ArrayView; use std::format; #[test] fn debug_only_shows_len_elements() { assert_eq!( "[1, 2]", &format!("{:?}", ArrayView::try_from_array([1, 2, 3, 4, 5], 2).unwrap()) ); } #[test] fn try_from_slice_too_long() { assert_eq!(None, ArrayView::::try_from_slice(&[1, 2, 3, 4, 5])); } #[test] fn try_from_slice_ok() { let view = ArrayView::::try_from_slice(&[1, 2, 3, 4, 5]).unwrap(); assert_eq!(&[1, 2, 3, 4, 5], view.as_slice()) } }