use super::posix; use core::{mem, ptr, slice}; use core::ops::{Deref, DerefMut}; fn must_succeed(p: *mut T) -> *mut T { if p.is_null() { panic!("allocation failure"); } p } fn malloc() -> *mut T { let size = mem::size_of::(); let align = mem::align_of::(); if size == 0 { return align as *mut T; } must_succeed( unsafe { libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T } ) } pub struct CBox(*mut T); impl CBox { pub fn new(value: T) -> CBox { let p = malloc(); unsafe { ptr::write(p, value); CBox::from_raw(p) } } pub const unsafe fn from_raw(p: *mut T) -> CBox { CBox(p) } pub fn into_raw(self) -> *mut T { let p = self.0; mem::forget(self); p } pub const fn as_ptr(&self) -> *const T { self.0 } pub fn as_mut_ptr(&mut self) -> *mut T { self.0 } } impl Drop for CBox { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.0); } if mem::size_of::() != 0 { unsafe { libc::free(self.0 as *mut libc::c_void); } } } } impl Deref for CBox { type Target = T; fn deref(&self) -> &T { unsafe { &*self.0 } } } impl DerefMut for CBox { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.0 } } } //pub struct FromBytesWithNulError {} pub struct CStr { inner: libc::c_char } impl CStr { pub unsafe fn from_ptr<'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 { &mut *(p as *mut CStr) } pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { CStr::from_ptr(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_bytes_mut(&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(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_ptr_mut(&mut *self.inner) } } } impl From<&[u8]> for CString { fn from(s: &[u8]) -> CString { unsafe { CString::from_raw(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(must_succeed(libc::strdup(s.as_ptr()))) } } }