tendril/
buf32.rs

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