| 1 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 2 | // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 3 | // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
| 4 | // option. This file may not be copied, modified, or distributed |
| 5 | // except according to those terms. |
| 6 | |
| 7 | //! Provides an unsafe owned buffer type, used in implementing `Tendril`. |
| 8 | |
| 9 | use std::{mem, ptr, slice, u32}; |
| 10 | |
| 11 | use OFLOW; |
| 12 | |
| 13 | pub const MIN_CAP: u32 = 16; |
| 14 | |
| 15 | pub const MAX_LEN: usize = u32::MAX as usize; |
| 16 | |
| 17 | /// A buffer points to a header of type `H`, which is followed by `MIN_CAP` or more |
| 18 | /// bytes of storage. |
| 19 | pub struct Buf32<H> { |
| 20 | pub ptr: *mut H, |
| 21 | pub len: u32, |
| 22 | pub cap: u32, |
| 23 | } |
| 24 | |
| 25 | #[inline (always)] |
| 26 | fn bytes_to_vec_capacity<H>(x: u32) -> usize { |
| 27 | let header: usize = mem::size_of::<H>(); |
| 28 | debug_assert!(header > 0); |
| 29 | let x: usize = (x as usize).checked_add(header).expect(msg:OFLOW); |
| 30 | // Integer ceil https://stackoverflow.com/a/2745086/1162888 |
| 31 | 1 + ((x - 1) / header) |
| 32 | } |
| 33 | |
| 34 | impl<H> Buf32<H> { |
| 35 | #[inline ] |
| 36 | pub unsafe fn with_capacity(mut cap: u32, h: H) -> Buf32<H> { |
| 37 | if cap < MIN_CAP { |
| 38 | cap = MIN_CAP; |
| 39 | } |
| 40 | |
| 41 | let mut vec = Vec::<H>::with_capacity(bytes_to_vec_capacity::<H>(cap)); |
| 42 | let ptr = vec.as_mut_ptr(); |
| 43 | mem::forget(vec); |
| 44 | ptr::write(ptr, h); |
| 45 | |
| 46 | Buf32 { |
| 47 | ptr: ptr, |
| 48 | len: 0, |
| 49 | cap: cap, |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | #[inline ] |
| 54 | pub unsafe fn destroy(self) { |
| 55 | mem::drop(Vec::from_raw_parts( |
| 56 | self.ptr, |
| 57 | 1, |
| 58 | bytes_to_vec_capacity::<H>(self.cap), |
| 59 | )); |
| 60 | } |
| 61 | |
| 62 | #[inline (always)] |
| 63 | pub unsafe fn data_ptr(&self) -> *mut u8 { |
| 64 | (self.ptr as *mut u8).offset(mem::size_of::<H>() as isize) |
| 65 | } |
| 66 | |
| 67 | #[inline (always)] |
| 68 | pub unsafe fn data(&self) -> &[u8] { |
| 69 | slice::from_raw_parts(self.data_ptr(), self.len as usize) |
| 70 | } |
| 71 | |
| 72 | #[inline (always)] |
| 73 | pub unsafe fn data_mut(&mut self) -> &mut [u8] { |
| 74 | slice::from_raw_parts_mut(self.data_ptr(), self.len as usize) |
| 75 | } |
| 76 | |
| 77 | /// Grow the capacity to at least `new_cap`. |
| 78 | /// |
| 79 | /// This will panic if the capacity calculation overflows `u32`. |
| 80 | #[inline ] |
| 81 | pub unsafe fn grow(&mut self, new_cap: u32) { |
| 82 | if new_cap <= self.cap { |
| 83 | return; |
| 84 | } |
| 85 | |
| 86 | let new_cap = new_cap.checked_next_power_of_two().expect(OFLOW); |
| 87 | let mut vec = Vec::from_raw_parts(self.ptr, 0, bytes_to_vec_capacity::<H>(self.cap)); |
| 88 | vec.reserve_exact(bytes_to_vec_capacity::<H>(new_cap)); |
| 89 | self.ptr = vec.as_mut_ptr(); |
| 90 | self.cap = new_cap; |
| 91 | mem::forget(vec); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | #[cfg (test)] |
| 96 | mod test { |
| 97 | use super::Buf32; |
| 98 | use std::ptr; |
| 99 | |
| 100 | #[test ] |
| 101 | fn smoke_test() { |
| 102 | unsafe { |
| 103 | let mut b = Buf32::with_capacity(0, 0u8); |
| 104 | assert_eq!(b"" , b.data()); |
| 105 | |
| 106 | b.grow(5); |
| 107 | ptr::copy_nonoverlapping(b"Hello" .as_ptr(), b.data_ptr(), 5); |
| 108 | |
| 109 | assert_eq!(b"" , b.data()); |
| 110 | b.len = 5; |
| 111 | assert_eq!(b"Hello" , b.data()); |
| 112 | |
| 113 | b.grow(1337); |
| 114 | assert!(b.cap >= 1337); |
| 115 | assert_eq!(b"Hello" , b.data()); |
| 116 | |
| 117 | b.destroy(); |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | |