| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| //! Provides an unsafe owned buffer type, used in implementing `Tendril`. |
| |
| use std::{mem, ptr, slice, u32}; |
| |
| use OFLOW; |
| |
| pub const MIN_CAP: u32 = 16; |
| |
| pub const MAX_LEN: usize = u32::MAX as usize; |
| |
| /// A buffer points to a header of type `H`, which is followed by `MIN_CAP` or more |
| /// bytes of storage. |
| pub struct Buf32<H> { |
| pub ptr: *mut H, |
| pub len: u32, |
| pub cap: u32, |
| } |
| |
| #[inline(always)] |
| fn bytes_to_vec_capacity<H>(x: u32) -> usize { |
| let header = mem::size_of::<H>(); |
| debug_assert!(header > 0); |
| let x = (x as usize).checked_add(header).expect(OFLOW); |
| // Integer ceil https://stackoverflow.com/a/2745086/1162888 |
| 1 + ((x - 1) / header) |
| } |
| |
| impl<H> Buf32<H> { |
| #[inline] |
| pub unsafe fn with_capacity(mut cap: u32, h: H) -> Buf32<H> { |
| if cap < MIN_CAP { |
| cap = MIN_CAP; |
| } |
| |
| let mut vec = Vec::<H>::with_capacity(bytes_to_vec_capacity::<H>(cap)); |
| let ptr = vec.as_mut_ptr(); |
| mem::forget(vec); |
| ptr::write(ptr, h); |
| |
| Buf32 { |
| ptr: ptr, |
| len: 0, |
| cap: cap, |
| } |
| } |
| |
| #[inline] |
| pub unsafe fn destroy(self) { |
| mem::drop(Vec::from_raw_parts( |
| self.ptr, |
| 1, |
| bytes_to_vec_capacity::<H>(self.cap), |
| )); |
| } |
| |
| #[inline(always)] |
| pub unsafe fn data_ptr(&self) -> *mut u8 { |
| (self.ptr as *mut u8).offset(mem::size_of::<H>() as isize) |
| } |
| |
| #[inline(always)] |
| pub unsafe fn data(&self) -> &[u8] { |
| slice::from_raw_parts(self.data_ptr(), self.len as usize) |
| } |
| |
| #[inline(always)] |
| pub unsafe fn data_mut(&mut self) -> &mut [u8] { |
| slice::from_raw_parts_mut(self.data_ptr(), self.len as usize) |
| } |
| |
| /// Grow the capacity to at least `new_cap`. |
| /// |
| /// This will panic if the capacity calculation overflows `u32`. |
| #[inline] |
| pub unsafe fn grow(&mut self, new_cap: u32) { |
| if new_cap <= self.cap { |
| return; |
| } |
| |
| let new_cap = new_cap.checked_next_power_of_two().expect(OFLOW); |
| let mut vec = Vec::from_raw_parts(self.ptr, 0, bytes_to_vec_capacity::<H>(self.cap)); |
| vec.reserve_exact(bytes_to_vec_capacity::<H>(new_cap)); |
| self.ptr = vec.as_mut_ptr(); |
| self.cap = new_cap; |
| mem::forget(vec); |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::Buf32; |
| use std::ptr; |
| |
| #[test] |
| fn smoke_test() { |
| unsafe { |
| let mut b = Buf32::with_capacity(0, 0u8); |
| assert_eq!(b"", b.data()); |
| |
| b.grow(5); |
| ptr::copy_nonoverlapping(b"Hello".as_ptr(), b.data_ptr(), 5); |
| |
| assert_eq!(b"", b.data()); |
| b.len = 5; |
| assert_eq!(b"Hello", b.data()); |
| |
| b.grow(1337); |
| assert!(b.cap >= 1337); |
| assert_eq!(b"Hello", b.data()); |
| |
| b.destroy(); |
| } |
| } |
| } |