Files
tor/src/rust/tor_util/rust_string.rs
T
Sebastian Hahn f8ef7c65d1 Add some Rust utility functions and print support
This gives an indication in the log that Tor was built with Rust
support, as well as laying some groundwork for further string-returning
APIs to be converted to Rust
2017-05-19 08:47:10 -04:00

102 lines
2.9 KiB
Rust

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<CString> 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<CString> 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::<RustString>())
}
}