blob: 46ec3fd7a8a99e8d25818f0c335d7f746166f344 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
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>())
}
}
|