use super::posix; use core::{mem, ptr, slice}; use core::ops::{Deref, DerefMut}; fn must_succeed(p: *mut T) -> *mut T { assert!(!p.is_null(), "allocation failure"); p } fn zst(count: usize) -> bool { mem::size_of::() == 0 || count == 0 } fn alloc(count: usize) -> *mut T { if zst::(count) { return ptr::null_mut(); } let size = count * mem::size_of::(); let align = mem::align_of::(); must_succeed( unsafe { libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T } ) } fn dangling() -> *mut T { mem::align_of::() as *mut T } fn check_ptr(p: *const T, len: usize) { debug_assert!((p as usize) % mem::align_of::() == 0, "unaligned ptr"); assert!(zst::(len) || !p.is_null(), "NULL ptr"); } fn slice_len(p: *const [T]) -> usize { unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] } } pub struct CBox(*mut T); impl CBox { pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox { 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 CBox { pub fn new(value: T) -> CBox { let p = alloc(1); unsafe { ptr::write(p, value); CBox::from_raw_unchecked(p) } } pub unsafe fn from_raw(p: *mut T) -> CBox { check_ptr(p, 1); CBox(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 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::(1), "NULL ptr"); return dangling(); } self.0 } } impl CBox<[T]> { fn safe_ptr(&self) -> *mut [T] { if self.0.is_null() { let len = slice_len(self.0); debug_assert!(zst::(len), "NULL ptr"); return ptr::slice_from_raw_parts_mut(dangling(), len); } self.0 } } impl Drop for CBox { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.0); libc::free(self.0 as *mut libc::c_void); } } } impl Deref for CBox { type Target = T; fn deref(&self) -> &T { unsafe { &*self.safe_ptr() } } } impl DerefMut for CBox { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.safe_ptr() } } } impl Deref for CBox<[T]> { type Target = [T]; fn deref(&self) -> &[T] { unsafe { &*self.safe_ptr() } } } impl DerefMut for CBox<[T]> { fn deref_mut(&mut self) -> &mut [T] { unsafe { &mut *self.safe_ptr() } } } //pub struct FromBytesWithNulError {} pub struct CStr { inner: libc::c_char } impl CStr { pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr { &*(p as *const 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_unchecked(bytes.as_ptr() as *const libc::c_char) } // TODO //pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { //} pub fn len(&self) -> usize { unsafe { libc::strlen(self.as_ptr()) as usize } } pub const fn as_ptr(&self) -> *const libc::c_char { &self.inner } pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { &mut self.inner } pub fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts( self.as_ptr() as *const u8, self.len(), ) } } pub fn as_mut_bytes(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut( self.as_mut_ptr() as *mut u8, self.len(), ) } } pub fn to_owned(self: &CStr) -> CString { CString::from(self) } } #[macro_export] macro_rules! cstr { ($s:expr) => ( unsafe { $crate::c::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) } ) } pub struct CString { inner: CBox } 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) } } pub fn into_raw(self) -> *mut libc::c_char { self.inner.into_raw() } } impl Deref for CString { type Target = CStr; fn deref(&self) -> &CStr { unsafe { CStr::from_ptr(&*self.inner) } } } impl DerefMut for CString { fn deref_mut(&mut self) -> &mut CStr { unsafe { CStr::from_mut_ptr(&mut *self.inner) } } } impl From<&[u8]> for CString { fn from(s: &[u8]) -> CString { unsafe { CString::from_raw_unchecked(must_succeed(posix::strndup( s.as_ptr() as *const libc::c_char, s.len() as libc::size_t, ))) } } } impl From<&str> for CString { fn from(s: &str) -> CString { CString::from(s.as_bytes()) } } impl From<&CStr> for CString { fn from(s: &CStr) -> CString { unsafe { CString::from_raw_unchecked(must_succeed(libc::strdup(s.as_ptr()))) } } }