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 | |