rust_string.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. use std::ffi::CString;
  2. use std::mem::forget;
  3. use libc;
  4. /// Compatibility wrapper for strings allocated in Rust and passed to C.
  5. ///
  6. /// Rust doesn't ensure the safety of freeing memory across an FFI boundary, so
  7. /// we need to take special care to ensure we're not accidentally calling
  8. /// `tor_free`() on any string allocated in Rust. To more easily differentiate
  9. /// between strings that possibly (if Rust support is enabled) were allocated
  10. /// in Rust, C has the `rust_str_t` helper type. The equivalent on the Rust
  11. /// side is `RustString`.
  12. ///
  13. /// Note: This type must not be used for strings allocated in C.
  14. #[repr(C)]
  15. #[derive(Debug)]
  16. pub struct RustString(*mut libc::c_char);
  17. impl RustString {
  18. /// Returns a pointer to the underlying NUL-terminated byte array.
  19. ///
  20. /// Note that this function is not typically useful for Rust callers,
  21. /// except in a direct FFI context.
  22. ///
  23. /// # Examples
  24. /// ```
  25. /// # use tor_util::RustString;
  26. /// use std::ffi::CString;
  27. ///
  28. /// let r = RustString::from(CString::new("asdf").unwrap());
  29. /// let c_str = r.as_ptr();
  30. /// assert_eq!(b'a', unsafe { *c_str as u8});
  31. /// ```
  32. pub fn as_ptr(&self) -> *const libc::c_char {
  33. self.0 as *const libc::c_char
  34. }
  35. }
  36. impl From<CString> for RustString {
  37. /// Constructs a new `RustString`
  38. ///
  39. /// # Examples
  40. /// ```
  41. /// # use tor_util::RustString;
  42. /// use std::ffi::CString;
  43. ///
  44. /// let r = RustString::from(CString::new("asdf").unwrap());
  45. /// ```
  46. fn from(str: CString) -> RustString {
  47. RustString(str.into_raw())
  48. }
  49. }
  50. impl Into<CString> for RustString {
  51. /// Reconstructs a `CString` from this `RustString`.
  52. ///
  53. /// Useful to take ownership back from a `RustString` that was given to C
  54. /// code.
  55. ///
  56. /// # Examples
  57. /// ```
  58. /// # use tor_util::RustString;
  59. /// use std::ffi::CString;
  60. ///
  61. /// let cs = CString::new("asdf").unwrap();
  62. /// let r = RustString::from(cs.clone());
  63. /// let cs2 = r.into();
  64. /// assert_eq!(cs, cs2);
  65. /// ```
  66. fn into(self) -> CString {
  67. // Calling from_raw is always OK here: We only construct self using
  68. // valid CStrings and don't expose anything that could mutate it
  69. let ret = unsafe { CString::from_raw(self.0) };
  70. forget(self);
  71. ret
  72. }
  73. }
  74. impl Drop for RustString {
  75. fn drop(&mut self) {
  76. // Don't use into() here, because we would need to move out of
  77. // self. Same safety consideration. Immediately drop the created
  78. // CString, which takes care of freeing the wrapped string.
  79. unsafe { CString::from_raw(self.0) };
  80. }
  81. }
  82. #[cfg(test)]
  83. mod test {
  84. use std::mem;
  85. use super::*;
  86. use libc;
  87. /// Ensures we're not adding overhead by using RustString.
  88. #[test]
  89. fn size_of() {
  90. assert_eq!(mem::size_of::<*mut libc::c_char>(),
  91. mem::size_of::<RustString>())
  92. }
  93. }