cpp_utils 0.1.0

Various C++-related types and functions needed for the cpp_to_rust project
Documentation
#[cfg(test)]
mod tests {
  use std::rc::Rc;
  use std::cell::RefCell;
  use {CppDeletable, Deleter, CppBox};

  struct Struct1 {
    value: Rc<RefCell<i32>>,
  }

  unsafe extern "C" fn struct1_delete(this_ptr: *mut Struct1) {
    (*this_ptr).value.borrow_mut().clone_from(&mut 42);
  }

  impl CppDeletable for Struct1 {
    fn deleter() -> Deleter<Self> {
      struct1_delete
    }
  }

  #[test]
  fn test_drop_calls_deleter() {
    let value1 = Rc::new(RefCell::new(10));
    let mut object1 = Struct1 {
      value: value1.clone()
    };
    assert!(value1.borrow().clone() == 10);
    unsafe {
      CppBox::new(&mut object1 as *mut _);
    }
    assert!(value1.borrow().clone() == 42);
  }
}

/// Deleter function type.
///
/// This is usually a C++ function imported via FFI
/// from a wrapper library. The body of this function
/// should be "delete this_ptr;".
pub type Deleter<T> = unsafe extern "C" fn(this_ptr: *mut T);

/// Indicates that the type can be put into a CppBox.
///
/// Example of implementation:
/// ```
/// impl CppDeletable for Struct1 {
///   fn deleter() -> Deleter<Self> {
///     struct1_delete
///   }
/// }
/// ```
pub trait CppDeletable : Sized {
  /// Returns deleter function for this type.
  fn deleter() -> Deleter<Self>;

}

/// A C++ pointer wrapper to manage deletion of objects.
///
/// Objects of CppBox should be created by calling into_box() for
/// types that implement CppDeletable trait. The object will
/// be deleted when corresponding CppBox is deleted.
pub struct CppBox<T> {
  ptr: *mut T,
  deleter: Deleter<T>,
}

impl<T> CppBox<T> {
  pub fn as_ptr(&self) -> *const T {
    self.ptr
  }
  pub fn as_mut_ptr(&self) -> *mut T {
    self.ptr
  }
  /// Returns the pointer that was used to create the object and destroys the box.
  /// The caller of the function becomes the owner of the object and should
  /// ensure that the object will be deleted at some point.
  pub fn unbox(self) -> *mut T {
    self.ptr
  }
}

impl<T: CppDeletable> CppBox<T> {
  /// Encapsulates the object into a CppBox.
  ///
  /// You should use this function only for
  /// pointers that were created on C++ side and passed through
  /// a FFI boundary to Rust. An object created with C++ "new"
  /// must be deleted using C++ "delete", which is executed by CppBox.
  ///
  /// Do not use this function for objects created in memory managed by Rust.
  /// Any wrapper constructor or function that returns an owned object
  /// is supposed to be deleted using Rust's ownage system and Drop trait.
  ///
  /// Do not use this function for objects that would be deleted by other means.
  /// If another C++ object is the owner of the passed object,
  /// it will attempt to delete it. Together with CppBox, it would result
  /// in a double deletion, which should never happen.
  pub unsafe fn new(ptr: *mut T) -> CppBox<T> {
    CppBox {
      ptr: ptr,
      deleter: CppDeletable::deleter()
    }
  }
}


impl<T> AsRef<T> for CppBox<T> {
  fn as_ref(&self) -> &T {
    unsafe {
      &*self.ptr
    }
  }
}

impl<T> AsMut<T> for CppBox<T> {
  fn as_mut(&mut self) -> &mut T {
    unsafe {
      &mut *self.ptr
    }
  }
}

impl<T> std::ops::Deref for CppBox<T> {
  type Target = T;
  fn deref(&self) -> &T {
    unsafe {
      &*self.ptr
    }
  }
}

impl<T> std::ops::DerefMut for CppBox<T> {
  fn deref_mut(&mut self) -> &mut T {
    unsafe {
      &mut *self.ptr
    }
  }
}

impl<T> Drop for CppBox<T> {
  fn drop(&mut self) {
    if !self.ptr.is_null() {
      unsafe {
        (self.deleter)(self.ptr);
      }
    }
  }
}

/// Additional argument for a function that returns a C++ object as Rust struct.
pub struct AsStruct;

/// Additional argument for a function that returns a C++ object as a pointer
/// enclosed in a CppBox.
pub struct AsBox;