use std::ffi::CString; use std::mem::forget; use libc; /// Compatibility wrapper for strings allocated in Rust and passed to C. /// /// Rust doesn't ensure the safety of freeing memory across an FFI boundary, so /// we need to take special care to ensure we're not accidentally calling /// `tor_free`() on any string allocated in Rust. To more easily differentiate /// between strings that possibly (if Rust support is enabled) were allocated /// in Rust, C has the `rust_str_t` helper type. The equivalent on the Rust /// side is `RustString`. /// /// Note: This type must not be used for strings allocated in C. #[repr(C)] #[derive(Debug)] pub struct RustString(*mut libc::c_char); impl RustString { /// Returns a pointer to the underlying NUL-terminated byte array. /// /// Note that this function is not typically useful for Rust callers, /// except in a direct FFI context. /// /// # Examples /// ``` /// # use tor_util::RustString; /// use std::ffi::CString; /// /// let r = RustString::from(CString::new("asdf").unwrap()); /// let c_str = r.as_ptr(); /// assert_eq!(b'a', unsafe { *c_str as u8}); /// ``` pub fn as_ptr(&self) -> *const libc::c_char { self.0 as *const libc::c_char } } impl From for RustString { /// Constructs a new `RustString` /// /// # Examples /// ``` /// # use tor_util::RustString; /// use std::ffi::CString; /// /// let r = RustString::from(CString::new("asdf").unwrap()); /// ``` fn from(str: CString) -> RustString { RustString(str.into_raw()) } } impl Into for RustString { /// Reconstructs a `CString` from this `RustString`. /// /// Useful to take ownership back from a `RustString` that was given to C /// code. /// /// # Examples /// ``` /// # use tor_util::RustString; /// use std::ffi::CString; /// /// let cs = CString::new("asdf").unwrap(); /// let r = RustString::from(cs.clone()); /// let cs2 = r.into(); /// assert_eq!(cs, cs2); /// ``` fn into(self) -> CString { // Calling from_raw is always OK here: We only construct self using // valid CStrings and don't expose anything that could mutate it let ret = unsafe { CString::from_raw(self.0) }; forget(self); ret } } impl Drop for RustString { fn drop(&mut self) { // Don't use into() here, because we would need to move out of // self. Same safety consideration. Immediately drop the created // CString, which takes care of freeing the wrapped string. unsafe { CString::from_raw(self.0) }; } } #[cfg(test)] mod test { use std::mem; use super::*; use libc; /// Ensures we're not adding overhead by using RustString. #[test] fn size_of() { assert_eq!(mem::size_of::<*mut libc::c_char>(), mem::size_of::()) } }