summaryrefslogtreecommitdiffstats
path: root/vendor/tendril/src/buf32.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tendril/src/buf32.rs')
-rw-r--r--vendor/tendril/src/buf32.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/vendor/tendril/src/buf32.rs b/vendor/tendril/src/buf32.rs
new file mode 100644
index 000000000..d60a277a1
--- /dev/null
+++ b/vendor/tendril/src/buf32.rs
@@ -0,0 +1,120 @@
+// 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();
+ }
+ }
+}