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
9use std::{mem, ptr, slice, u32};
10
11use OFLOW;
12
13pub const MIN_CAP: u32 = 16;
14
15pub 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.
19pub struct Buf32<H> {
20 pub ptr: *mut H,
21 pub len: u32,
22 pub cap: u32,
23}
24
25#[inline(always)]
26fn 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
34impl<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)]
96mod 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