summaryrefslogtreecommitdiffstats
path: root/src/c/string.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/c/string.rs')
-rw-r--r--src/c/string.rs144
1 files changed, 111 insertions, 33 deletions
diff --git a/src/c/string.rs b/src/c/string.rs
index eef6371..3d991dc 100644
--- a/src/c/string.rs
+++ b/src/c/string.rs
@@ -3,18 +3,20 @@ use core::{mem, ptr, slice};
use core::ops::{Deref, DerefMut};
fn must_succeed<T>(p: *mut T) -> *mut T {
- if p.is_null() {
- panic!("allocation failure");
- }
+ assert!(!p.is_null(), "allocation failure");
p
}
-fn malloc<T>() -> *mut T {
- let size = mem::size_of::<T>();
- let align = mem::align_of::<T>();
- if size == 0 {
- return align as *mut T;
+fn zst<T>(count: usize) -> bool {
+ mem::size_of::<T>() == 0 || count == 0
+}
+
+fn alloc<T>(count: usize) -> *mut T {
+ if zst::<T>(count) {
+ return ptr::null_mut();
}
+ let size = count * mem::size_of::<T>();
+ let align = mem::align_of::<T>();
must_succeed(
unsafe {
libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T
@@ -22,43 +24,91 @@ fn malloc<T>() -> *mut T {
)
}
-pub struct CBox<T>(*mut T);
+fn dangling<T>() -> *mut T {
+ mem::align_of::<T>() as *mut T
+}
+
+fn check_ptr<T>(p: *const T, len: usize) {
+ debug_assert!((p as usize) % mem::align_of::<T>() == 0, "unaligned ptr");
+ assert!(zst::<T>(len) || !p.is_null(), "NULL ptr");
+}
+
+fn slice_len<T>(p: *const [T]) -> usize {
+ unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] }
+}
+
+pub struct CBox<T: ?Sized>(*mut T);
+
+impl<T: ?Sized> CBox<T> {
+ pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> {
+ CBox(p)
+ }
+
+ pub fn into_raw(self) -> *mut T {
+ let p = self.0;
+ mem::forget(self);
+ p
+ }
+
+ pub fn as_ptr(&self) -> *const T {
+ self.0
+ }
+
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self.0
+ }
+}
impl<T> CBox<T> {
pub fn new(value: T) -> CBox<T> {
- let p = malloc();
+ let p = alloc(1);
unsafe {
ptr::write(p, value);
- CBox::from_raw(p)
+ CBox::from_raw_unchecked(p)
}
}
- pub const unsafe fn from_raw(p: *mut T) -> CBox<T> {
+ pub unsafe fn from_raw(p: *mut T) -> CBox<T> {
+ check_ptr(p, 1);
CBox(p)
}
- pub fn into_raw(self) -> *mut T {
- let p = self.0;
- mem::forget(self);
- p
+ pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> {
+ CBox(ptr::slice_from_raw_parts_mut(p, len))
}
- pub const fn as_ptr(&self) -> *const T {
+ pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> {
+ check_ptr(p, len);
+ CBox::slice_from_raw_parts_unchecked(p, len)
+ }
+
+ fn safe_ptr(&self) -> *mut T {
+ if self.0.is_null() {
+ debug_assert!(zst::<T>(1), "NULL ptr");
+ return dangling();
+ }
+
self.0
}
+}
+
+impl<T> CBox<[T]> {
+ fn safe_ptr(&self) -> *mut [T] {
+ if self.0.is_null() {
+ let len = slice_len(self.0);
+ debug_assert!(zst::<T>(len), "NULL ptr");
+ return ptr::slice_from_raw_parts_mut(dangling(), len);
+ }
- pub fn as_mut_ptr(&mut self) -> *mut T {
self.0
}
}
-impl<T> Drop for CBox<T> {
+impl<T: ?Sized> Drop for CBox<T> {
fn drop(&mut self) {
- unsafe { ptr::drop_in_place(self.0); }
- if mem::size_of::<T>() != 0 {
- unsafe {
- libc::free(self.0 as *mut libc::c_void);
- }
+ unsafe {
+ ptr::drop_in_place(self.0);
+ libc::free(self.0 as *mut libc::c_void);
}
}
}
@@ -67,13 +117,27 @@ impl<T> Deref for CBox<T> {
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.0 }
+ unsafe { &*self.safe_ptr() }
}
}
impl<T> DerefMut for CBox<T> {
fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.0 }
+ unsafe { &mut *self.safe_ptr() }
+ }
+}
+
+impl<T> Deref for CBox<[T]> {
+ type Target = [T];
+
+ fn deref(&self) -> &[T] {
+ unsafe { &*self.safe_ptr() }
+ }
+}
+
+impl<T> DerefMut for CBox<[T]> {
+ fn deref_mut(&mut self) -> &mut [T] {
+ unsafe { &mut *self.safe_ptr() }
}
}
@@ -82,16 +146,26 @@ impl<T> DerefMut for CBox<T> {
pub struct CStr { inner: libc::c_char }
impl CStr {
- pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
+ pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr {
&*(p as *const CStr)
}
- pub unsafe fn from_ptr_mut<'a>(p: *mut libc::c_char) -> &'a mut CStr {
+ pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr {
+ check_ptr(p, 1);
+ CStr::from_ptr_unchecked(p)
+ }
+
+ pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr {
&mut *(p as *mut CStr)
}
+ pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr {
+ check_ptr(p, 1);
+ CStr::from_mut_ptr_unchecked(p)
+ }
+
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- CStr::from_ptr(bytes.as_ptr() as *const libc::c_char)
+ CStr::from_ptr_unchecked(bytes.as_ptr() as *const libc::c_char)
}
// TODO
@@ -117,7 +191,7 @@ impl CStr {
) }
}
- pub fn as_bytes_mut(&mut self) -> &mut [u8] {
+ pub fn as_mut_bytes(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(
self.as_mut_ptr() as *mut u8,
self.len(),
@@ -139,6 +213,10 @@ macro_rules! cstr {
pub struct CString { inner: CBox<libc::c_char> }
impl CString {
+ pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString {
+ CString { inner: CBox::from_raw_unchecked(p) }
+ }
+
pub unsafe fn from_raw(p: *mut libc::c_char) -> CString {
CString { inner: CBox::from_raw(p) }
}
@@ -158,14 +236,14 @@ impl Deref for CString {
impl DerefMut for CString {
fn deref_mut(&mut self) -> &mut CStr {
- unsafe { CStr::from_ptr_mut(&mut *self.inner) }
+ unsafe { CStr::from_mut_ptr(&mut *self.inner) }
}
}
impl From<&[u8]> for CString {
fn from(s: &[u8]) -> CString {
unsafe {
- CString::from_raw(must_succeed(posix::strndup(
+ CString::from_raw_unchecked(must_succeed(posix::strndup(
s.as_ptr() as *const libc::c_char,
s.len() as libc::size_t,
)))
@@ -182,7 +260,7 @@ impl From<&str> for CString {
impl From<&CStr> for CString {
fn from(s: &CStr) -> CString {
unsafe {
- CString::from_raw(must_succeed(libc::strdup(s.as_ptr())))
+ CString::from_raw_unchecked(must_succeed(libc::strdup(s.as_ptr())))
}
}
}