// Copyright 2024, The Android Open Source Project // // 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. //! ImageBuffer is helper to store uninitialized memory buffer. And work with it allowing to read //! into the buffer and retrieve initialized part. //! //! Similar to [ReadBuf](https://docs.rs/tokio/latest/tokio/io/struct.ReadBuf.html) but works in //! `no_std`. use core::mem::MaybeUninit; use liberror::{Error, Result}; /// Wrapper class for buffer received with [get_buffer] function. /// /// Helps to keep track of allocated/init memory and avoid getting same buffer more than once. #[derive(Debug)] pub struct ImageBuffer<'a> { buffer: Option<&'a mut [MaybeUninit]>, // number of initialized and filled bytes. used_bytes: usize, } // Unstable MaybeUninit API // feature = "maybe_uninit_slice", issue = "63569" // Assuming all the elements are initialized, get a mutable slice to them. // // # Safety // // It is up to the caller to guarantee that the `MaybeUninit` elements // really are in an initialized state. // Calling this when the content is not yet fully initialized causes undefined behavior. #[inline(always)] unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit]) -> &mut [T] { // SAFETY: Caller must make sure provided data is initialized. unsafe { &mut *(slice as *mut [MaybeUninit] as *mut [T]) } } // Assuming all the elements are initialized, get a slice of them. // // # Safety // // It is up to the caller to guarantee that the `MaybeUninit` elements // really are in an initialized state. // Calling this when the content is not yet fully initialized causes undefined behavior. #[inline(always)] unsafe fn slice_assume_init_ref(slice: &[MaybeUninit]) -> &[T] { // SAFETY: Caller must make sure provided data is initialized. unsafe { &*(slice as *const [MaybeUninit] as *const [T]) } } impl ImageBuffer<'_> { /// Create new ImageBuffer from buffer and used_bytes pub fn new(buffer: &mut [MaybeUninit]) -> ImageBuffer { ImageBuffer { buffer: Some(buffer), used_bytes: 0 } } /// Total buffer capacity. pub fn capacity(&self) -> usize { self.buffer.as_ref().unwrap().len() } /// Increase used part of the buffer by `len` /// /// Return: /// Error() - if current used_bytes + len > capacity, or causes arithmetic overflow. /// Ok(()) - on success /// /// SAFETY: /// It is up to the user to guarantee that `len` bytes for tail was initialized and filled. pub unsafe fn advance_used(&mut self, len: usize) -> Result<()> { let Some(new_len) = self.used_bytes.checked_add(len) else { return Err(Error::Other(Some("Used bytes overflow"))); }; if new_len > self.capacity() { return Err(Error::BufferTooSmall(Some(new_len))); } self.used_bytes = new_len; Ok(()) } /// Return used and tail parts of the buffer pub fn get_split(&self) -> (&[u8], &[MaybeUninit]) { let (used, tail) = self.buffer.as_ref().unwrap().split_at(self.used_bytes); // SAFETY: // // ImageBuffer user guarantees that changing used elements means they were initialized. // And object assumes initialized only for slice [..used_bytes] let initialized = unsafe { slice_assume_init_ref(used) }; (initialized, tail) } /// Return used and tail parts of the buffer pub fn get_split_mut(&mut self) -> (&mut [u8], &mut [MaybeUninit]) { let (used, tail) = self.buffer.as_mut().unwrap().split_at_mut(self.used_bytes); // SAFETY: // // ImageBuffer user guaranties that changing used elements means they were initialized. // And object assumes initialized only for slice [..used_bytes] let initialized = unsafe { slice_assume_init_mut(used) }; (initialized, tail) } /// Slice of the buffer that is used pub fn used(&self) -> &[u8] { let (used, _) = self.get_split(); used } /// Slice of the buffer that is used pub fn used_mut(&mut self) -> &mut [u8] { let (used, _) = self.get_split_mut(); used } /// Return part of the buffer that is not used pub fn tail(&mut self) -> &mut [MaybeUninit] { let (_, tail) = self.get_split_mut(); tail } } impl AsRef<[MaybeUninit]> for ImageBuffer<'_> { fn as_ref(&self) -> &[MaybeUninit] { self.buffer.as_ref().unwrap() } } impl AsMut<[MaybeUninit]> for ImageBuffer<'_> { fn as_mut(&mut self) -> &mut [MaybeUninit] { self.buffer.as_mut().unwrap() } } impl PartialEq for ImageBuffer<'_> { fn eq(&self, other: &Self) -> bool { self.used() == other.used() } } #[cfg(test)] /// Helper to create ImageBuffers from Vec pub struct ImageBufferVec { buf: Vec, } #[cfg(test)] impl ImageBufferVec { pub fn new(buf: Vec) -> Self { Self { buf } } pub fn get(&mut self) -> ImageBuffer { ImageBuffer::new(Self::slice_assume_not_init_mut(self.buf.as_mut_slice())) } fn slice_assume_not_init_mut(slice: &mut [T]) -> &mut [MaybeUninit] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [T] as *mut [MaybeUninit]) } } } #[cfg(test)] mod test { use super::*; #[test] fn test_image_buffer_capacity() { assert_eq!(ImageBufferVec::new(vec![0u8; 0]).get().capacity(), 0); assert_eq!(ImageBufferVec::new(vec![0u8; 0]).get().capacity(), 0); assert_eq!(ImageBufferVec::new(vec![0u8; 1]).get().capacity(), 1); assert_eq!(ImageBufferVec::new(vec![0u8; 100]).get().capacity(), 100); assert_eq!( ImageBufferVec::new(vec![0u8; 128 * 1024 * 1024]).get().capacity(), 128 * 1024 * 1024 ); } #[test] fn test_image_buffer_used() { let mut img_buf_vec = ImageBufferVec::new(vec![0u8; 100]); let mut img_buf = img_buf_vec.get(); assert_eq!(img_buf.used().len(), 0); assert_eq!(img_buf.used_mut().len(), 0); // SAFETY: // All data in img_buf is initialized since it was created from vec unsafe { img_buf.advance_used(1).unwrap() }; assert_eq!(img_buf.used().len(), 1); assert_eq!(img_buf.used_mut().len(), 1); // SAFETY: // All data in img_buf is initialized since it was created from vec unsafe { img_buf.advance_used(3).unwrap() }; assert_eq!(img_buf.used().len(), 4); assert_eq!(img_buf.used_mut().len(), 4); assert_eq!( // SAFETY: // All data in img_buf is initialized since it was created from vec unsafe { img_buf.advance_used(1024) }, Err(Error::BufferTooSmall(Some(1028))) ); assert_eq!(img_buf.used().len(), 4); assert_eq!(img_buf.used_mut().len(), 4); } #[test] fn test_image_buffer_get_split() { let mut img_buf_vec = ImageBufferVec::new(vec![0u8, 1, 2, 3]); let mut img_buf = img_buf_vec.get(); assert_eq!(img_buf.used(), [].as_slice()); assert_eq!(img_buf.used_mut(), [].as_mut_slice()); assert_eq!(img_buf.tail().len(), 4); let (used, tail) = img_buf.get_split(); assert_eq!(used, [].as_slice()); assert_eq!(tail.len(), 4); let (used, tail) = img_buf.get_split_mut(); assert_eq!(used, [].as_mut_slice()); assert_eq!(tail.len(), 4); // SAFETY: // All data in img_buf is initialized since it was created from vec unsafe { img_buf.advance_used(2).unwrap() }; assert_eq!(img_buf.used(), [0, 1].as_slice()); assert_eq!(img_buf.used_mut(), [0, 1].as_mut_slice()); assert_eq!(img_buf.tail().len(), 2); let (used, tail) = img_buf.get_split(); assert_eq!(used, [0, 1].as_slice()); assert_eq!(tail.len(), 2); let (used, tail) = img_buf.get_split_mut(); assert_eq!(used, [0, 1].as_mut_slice()); assert_eq!(tail.len(), 2); // SAFETY: // All data in img_buf is initialized since it was created from vec unsafe { img_buf.advance_used(2).unwrap() }; assert_eq!(img_buf.used(), [0, 1, 2, 3].as_slice()); assert_eq!(img_buf.used_mut(), [0, 1, 2, 3].as_mut_slice()); assert_eq!(img_buf.tail().len(), 0); let (used, tail) = img_buf.get_split(); assert_eq!(used, [0, 1, 2, 3].as_slice()); assert_eq!(tail.len(), 0); let (used, tail) = img_buf.get_split_mut(); assert_eq!(used, [0, 1, 2, 3].as_mut_slice()); assert_eq!(tail.len(), 0); } #[test] fn test_image_buffer_eq_not_init() { assert_eq!( ImageBufferVec::new(vec![0u8, 1, 2]).get(), ImageBufferVec::new(vec![0u8, 1, 2]).get() ); } #[test] fn test_image_buffer_eq_init_same() { let mut v1 = ImageBufferVec::new(vec![0u8, 1, 2]); let mut v2 = ImageBufferVec::new(vec![0u8, 1, 2]); let mut image_buffer_1 = v1.get(); let mut image_buffer_2 = v2.get(); // SAFETY: // Buffers initialised on creation. unsafe { image_buffer_1.advance_used(3).unwrap(); image_buffer_2.advance_used(3).unwrap(); } assert_eq!(image_buffer_1, image_buffer_2); } #[test] fn test_image_buffer_eq_diff_capacity() { let mut v1 = ImageBufferVec::new(vec![0u8, 1, 2]); let mut v2 = ImageBufferVec::new(vec![0u8, 1, 2, 3]); let mut image_buffer_1 = v1.get(); let mut image_buffer_2 = v2.get(); // SAFETY: // Buffers initialised on creation. unsafe { image_buffer_1.advance_used(2).unwrap(); image_buffer_2.advance_used(2).unwrap(); } assert_eq!(image_buffer_1, image_buffer_2); } }