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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#[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 into_raw(mut self) -> *mut T {
    let ptr = self.ptr;
    self.ptr = std::ptr::null_mut();
    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;

/// This module contains `NewUninitialized` trait which should not be used directly.
pub mod new_uninitialized {

  /// A trait for types that can be created with
  /// uninitialized internal buffer.
  ///
  /// This trait should not be used directly.
  /// It's only useful for the code automatically generated
  /// by cpp_to_rust.
  pub trait NewUninitialized {
    /// Creates new object with
    /// uninitialized internal buffer.
    unsafe fn new_uninitialized() -> Self;
  }
}

/// Provides access to C++ `static_cast` conversion from derived class to base class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `StaticCast<T2>` is implemented for `T1`.
///
/// `StaticCast` allows to convert a reference to a class into
/// a reference to a base class.
///
/// `static_cast` and `static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait StaticCast<T> {
  /// Convert type of a const reference.
  fn static_cast(&self) -> &T;
  /// Convert type of a mutable reference.
  fn static_cast_mut(&mut self) -> &mut T;
}

/// Converts type of a const pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub fn static_cast<R, T: StaticCast<R>>(ptr: *const T) -> *const R {
  unsafe { ptr.as_ref() }.map(|x| x.static_cast() as *const R).unwrap_or(std::ptr::null())
}

/// Converts type of a mutable pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub fn static_cast_mut<R, T: StaticCast<R>>(ptr: *mut T) -> *mut R {
  unsafe { ptr.as_mut() }.map(|x| x.static_cast_mut() as *mut R).unwrap_or(std::ptr::null_mut())
}

/// Provides access to C++ `static_cast` conversion from base class to derived class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `UnsafeStaticCast<T1>` is implemented for `T2`.
///
/// `UnsafeStaticCast` allows to convert a reference to a class into
/// a reference to a derived class without runtime check of the type.
/// Casting from base class type to a derived class type which is
/// not the actual type of the object will result in an invalid reference.
///
/// `unsafe_static_cast` and `unsafe_static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait UnsafeStaticCast<T> {
  /// Convert type of a const reference.
  unsafe fn static_cast(&self) -> &T;
  /// Convert type of a mutable reference.
  unsafe fn static_cast_mut(&mut self) -> &mut T;
}

/// Converts type of a const pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn unsafe_static_cast<R, T: UnsafeStaticCast<R>>(ptr: *const T) -> *const R {
  ptr.as_ref().map(|x| x.static_cast() as *const R).unwrap_or(std::ptr::null())
}

/// Converts type of a mutable pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn unsafe_static_cast_mut<R, T: UnsafeStaticCast<R>>(ptr: *mut T) -> *mut R {
  ptr.as_mut().map(|x| x.static_cast_mut() as *mut R).unwrap_or(std::ptr::null_mut())
}


/// Provides access to C++ `dynamic_cast` conversion.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `DynamicCast<T1>` is implemented for `T2`.
/// Use `StaticCast` to convert from `T1` to `T2`.
///
/// `DynamicCast` allows to convert a reference to a class into
/// a reference to a derived class with a runtime check of the type.
/// Conversion returns `None` if the object is actually not an instance of
/// the target type.
///
/// `dynamic_cast` and `dynamic_cast_mut` free functions can be used
/// to convert pointer types.
pub trait DynamicCast<T> {
  /// Convert type of a const reference.
  /// Returns `None` if `self` is not an instance of `T`.
  fn dynamic_cast(&self) -> Option<&T>;
  /// Convert type of a mutable reference.
  /// Returns `None` if `self` is not an instance of `T`.
  fn dynamic_cast_mut(&mut self) -> Option<&mut T>;
}

/// Converts type of a const pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R` or an instance of
/// a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn dynamic_cast<R, T: DynamicCast<R>>(ptr: *const T) -> *const R {
  ptr.as_ref().and_then(|x| x.dynamic_cast()).map(|x| x as *const R).unwrap_or(std::ptr::null())
}

/// Converts type of a mutable pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn dynamic_cast_mut<R, T: DynamicCast<R>>(ptr: *mut T) -> *mut R {
  ptr.as_mut().and_then(|x| x.dynamic_cast_mut()).map(|x| x as *mut R).unwrap_or(std::ptr::null_mut())
}