blob: 0d101f9456cae568a6601c88a03b6ff2cfde33d1 [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use core::ops::Deref;
use core::ops::DerefMut;
/// An owned block of mutable bytes. This is effectively a newtype wrapper for
/// `&'static mut [u8]` that makes code look a little nicer, especially when you
/// have references. e.g. `&MemBlock` looks nicer than `&&'static mut [u8]`.
pub struct MemBlock {
data: &'static mut [u8],
/// The size of the original allocation if it was allocated on the heap. It
/// is critical when we reconstruct the Vec to free it, that we do so with
/// the same capacity as the original Vec. Will be None if `data` didn't
/// originate from the heap.
#[cfg(any(feature = "std", test))]
on_heap_capacity: Option<usize>,
}
impl MemBlock {
/// It's safe to call this function, however some code somewhere will need
/// to use unsafe in order to obtain the &'static mut that this function
/// takes ownership of. It is the job of that code to make sure that it can
/// only be called once, thus preventing aliasing.
pub fn new(data: &'static mut [u8]) -> Self {
Self {
data,
#[cfg(any(feature = "std", test))]
on_heap_capacity: None,
}
}
/// Constructs a new instance on the heap with the requested capacity.
#[cfg(any(feature = "std", test))]
pub fn with_capacity(capacity: usize) -> Self {
let v = vec![0; capacity];
let on_heap_capacity = Some(v.capacity());
Self {
data: Vec::leak(v),
on_heap_capacity,
}
}
}
impl Deref for MemBlock {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&*self.data
}
}
impl DerefMut for MemBlock {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.data
}
}
#[cfg(any(feature = "std", test))]
impl Drop for MemBlock {
fn drop(&mut self) {
if let Some(capacity) = self.on_heap_capacity {
// Safety: We're reconstructing a Vec using a pointer that was
// obtained originally from a Vec. The alignment and capacity are
// the same. The length doesn't matter, as long as it's less than
// the capacity.
unsafe { Vec::from_raw_parts(self.data.as_mut_ptr(), 0, capacity) };
}
}
}