// Take a look at the license at the top of the repository in the LICENSE file. use core_foundation_sys::base::CFRelease; use libc::c_char; use std::ptr::NonNull; // A helper using to auto release the resource got from CoreFoundation. // More information about the ownership policy for CoreFoundation pelease refer the link below: // https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-CJBEJBHH #[repr(transparent)] pub(crate) struct CFReleaser(NonNull); impl CFReleaser { pub(crate) fn new(ptr: *const T) -> Option { // This cast is OK because `NonNull` is a transparent wrapper // over a `*const T`. Additionally, mutability doesn't matter with // pointers here. NonNull::new(ptr as *mut T).map(Self) } pub(crate) fn inner(&self) -> *const T { self.0.as_ptr().cast() } } impl Drop for CFReleaser { fn drop(&mut self) { unsafe { CFRelease(self.0.as_ptr().cast()) } } } // Safety: These are safe to implement because we only wrap non-mutable // CoreFoundation types, which are generally threadsafe unless noted // otherwise. unsafe impl Send for CFReleaser {} unsafe impl Sync for CFReleaser {} pub(crate) fn cstr_to_rust(c: *const c_char) -> Option { cstr_to_rust_with_size(c, None) } pub(crate) fn cstr_to_rust_with_size(c: *const c_char, size: Option) -> Option { if c.is_null() { return None; } let mut s = match size { Some(len) => Vec::with_capacity(len), None => Vec::new(), }; let mut i = 0; unsafe { loop { let value = *c.offset(i) as u8; if value == 0 { break; } s.push(value); i += 1; } String::from_utf8(s).ok() } } pub(crate) fn vec_to_rust(buf: Vec) -> Option { String::from_utf8( buf.into_iter() .flat_map(|b| if b > 0 { Some(b as u8) } else { None }) .collect(), ) .ok() }