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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
use crate::ops::{Begin, BeginMut, End, EndMut, Increment, Indirection};
use crate::vector_ops::{Data, DataMut, Size};
use crate::{cpp_iter, CppIterator, DynamicCast, Ptr, Ref, StaticDowncast, StaticUpcast};
use std::ops::Deref;
use std::{fmt, mem, ptr, slice};

/// Objects that can be deleted using C++'s `delete` operator.
///
/// This trait is automatically implemented for class types by `ritual`.
pub trait CppDeletable: Sized {
    /// Calls C++'s `delete x` on `self`.
    ///
    /// # Safety
    ///
    /// The caller must make sure `self` contains a valid pointer. This function
    /// may invoke arbitrary foreign code, so no safety guarantees can be made.
    /// Note that deleting an object multiple times is undefined behavior.
    unsafe fn delete(&self);
}

/// An owning pointer to a C++ object.
///
/// `CppBox` is automatically used in places where C++ class objects are passed by value
/// and in return values of constructors because the ownership is apparent in these cases.
/// However, sometimes an object is returned as a pointer but you must accept the ownership
/// of the object. It's not possible to automatically determine ownership semantics
/// of C++ code in this case, so you should manually convert `Ptr` to `CppBox`
/// using `to_box` method.
///
/// When `CppBox` is dropped, it will automatically delete the object using C++'s `delete`
/// operator.
///
/// Objects stored in `CppBox` are usually placed on the heap by the C++ code.
///
/// If a C++ API accepts an object by pointer and takes ownership of it, it's not possible to
/// automatically detect this, so you must manually convert `CppBox` to a non-owning `Ptr`
/// using `into_ptr` before passing it to such a function.
///
/// `&CppBox<T>` and `&mut CppBox<T>` implement operator traits and delegate them
/// to the corresponding C++ operators.
/// This means that you can use `&box1 + value` to access the object's `operator+`.
///
/// `CppBox` implements `Deref`, allowing to call the object's methods
/// directly. In addition, methods of the object's first base class are also directly available
/// thanks to nested `Deref` implementations.
///
/// If the object provides an iterator interface through `begin()` and `end()` functions,
/// `&CppBox<T>` and `&mut CppBox<T>` will implement `IntoIterator`,
/// so you can iterate on them directly.
///
/// ### Safety
///
/// It's not possible to automatically track the ownership of objects possibly managed by C++
/// libraries. The user must ensure that the object is alive while `CppBox` exists and that
/// no pointers to the object are used after the object is deleted
/// by `CppBox`'s `Drop` implementation. Note that with `CppBox`,
/// it's possible to call unsafe C++ code without using any more unsafe code, for example, by
/// using operator traits or simply dropping the box, so care should be taken when exposing
/// `CppBox` in a safe interface.
pub struct CppBox<T: CppDeletable>(ptr::NonNull<T>);

impl<T: CppDeletable> CppBox<T> {
    /// Encapsulates the object into a `CppBox`. Returns `None` if the pointer is null.
    ///
    /// The same operation can be done by calling `to_box` function on `Ptr`.
    ///
    /// 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 that would be deleted by other means.
    /// If another C++ object is the owner of the passed object,
    /// it will attempt to delete it. If `CppBox` containing the object still exists,
    /// it would result in a double deletion, which must never happen.
    ///
    /// Use `CppBox::into_ptr` to unwrap the pointer before passing it to
    /// a function that takes ownership of the object.
    ///
    /// ### Safety
    ///
    /// The pointer must point to an object that can be
    /// safely deleted using C++'s `delete` operator.
    /// The object must not be deleted by other means while `CppBox` exists.
    /// Any other pointers to the object must not be used after `CppBox` is dropped.
    pub unsafe fn new(ptr: Ptr<T>) -> Option<Self> {
        Self::from_raw(ptr.as_raw_ptr())
    }

    /// Encapsulates the object into a `CppBox`. Returns `None` if the pointer is null.
    ///
    /// See `CppBox::new` for more information.
    ///
    /// ### Safety
    ///
    /// The pointer must point to an object that can be
    /// safely deleted using C++'s `delete` operator.
    /// The object must not be deleted by other means while `CppBox` exists.
    /// Any other pointers to the object must not be used after `CppBox` is dropped.
    pub unsafe fn from_raw(ptr: *const T) -> Option<Self> {
        ptr::NonNull::new(ptr as *mut T).map(CppBox)
    }

    /// Returns a constant pointer to the value in the box.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    pub unsafe fn as_ptr(&self) -> Ptr<T> {
        Ptr::from_raw(self.0.as_ptr())
    }

    /// Returns a constant raw pointer to the value in the box.
    pub fn as_mut_raw_ptr(&self) -> *mut T {
        self.0.as_ptr()
    }

    /// Returns a mutable raw pointer to the value in the box.
    pub fn as_raw_ptr(&self) -> *const T {
        self.0.as_ptr() as *const T
    }

    /// Destroys the box without deleting the object and returns a raw pointer to the content.
    /// 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_ptr(self) -> *mut T {
        let ptr = self.0.as_ptr();
        mem::forget(self);
        ptr
    }

    /// Destroys the box without deleting the object and returns a pointer to the content.
    /// The caller of the function becomes the owner of the object and should
    /// ensure that the object will be deleted at some point.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    pub unsafe fn into_ptr(self) -> Ptr<T> {
        let ptr = Ptr::from_raw(self.0.as_ptr());
        mem::forget(self);
        ptr
    }

    /// Returns a constant reference to the value in the box.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    #[allow(clippy::should_implement_trait)]
    pub unsafe fn as_ref(&self) -> Ref<T> {
        Ref::from_raw_non_null(self.0)
    }

    /// Returns a reference to the value.
    ///
    /// ### Safety
    ///
    /// `self` must be valid.
    /// The content must not be read or modified through other ways while the returned reference
    /// exists.See type level documentation.
    pub unsafe fn as_raw_ref<'a>(&self) -> &'a T {
        &*self.0.as_ptr()
    }

    /// Returns a mutable reference to the value.
    ///
    /// ### Safety
    ///
    /// `self` must be valid.
    /// The content must not be read or modified through other ways while the returned reference
    /// exists.See type level documentation.
    pub unsafe fn as_mut_raw_ref<'a>(&self) -> &'a mut T {
        &mut *self.0.as_ptr()
    }

    /// Returns a non-owning reference to the content converted to the base class type `U`.
    /// `CppBox` retains the ownership of the object.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    pub unsafe fn static_upcast<U>(&self) -> Ref<U>
    where
        T: StaticUpcast<U>,
    {
        StaticUpcast::static_upcast(self.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on CppBox input")
    }

    /// Returns a non-owning reference to the content converted to the derived class type `U`.
    /// `CppBox` retains the ownership of the object.
    ///
    /// It's recommended to use `dynamic_cast` instead because it performs a checked conversion.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid and it's type is `U` or inherits from `U`.
    pub unsafe fn static_downcast<U>(&self) -> Ref<U>
    where
        T: StaticDowncast<U>,
    {
        StaticDowncast::static_downcast(self.as_ptr())
            .as_ref()
            .expect("StaticDowncast returned null on CppBox input")
    }

    /// Returns a non-owning reference to the content converted to the derived class type `U`.
    /// `CppBox` retains the ownership of the object. Returns `None` if the object's type is not `U`
    /// and doesn't inherit `U`.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    pub unsafe fn dynamic_cast<U>(&self) -> Option<Ref<U>>
    where
        T: DynamicCast<U>,
    {
        DynamicCast::dynamic_cast(self.as_ptr()).as_ref()
    }
}

impl<V, T> CppBox<V>
where
    V: Data<Output = *const T> + Size + CppDeletable,
{
    /// Returns the content of the object as a slice, based on `data()` and `size()` methods.
    ///
    /// # Safety
    ///
    /// The caller must make sure `self` contains a valid pointer. The content must
    /// not be read or modified through other ways while the returned slice exists.
    /// This function
    /// may invoke arbitrary foreign code, so no safety guarantees can be made.
    pub unsafe fn as_slice<'a>(&self) -> &'a [T] {
        let ptr = self.data();
        let size = self.size();
        slice::from_raw_parts(ptr, size)
    }
}

impl<V, T> CppBox<V>
where
    V: DataMut<Output = *mut T> + Size + CppDeletable,
{
    /// Returns the content of the vector as a mutable slice,
    /// based on `data()` and `size()` methods.
    ///
    /// # Safety
    ///
    /// The caller must make sure `self` contains a valid pointer. The content must
    /// not be read or modified through other ways while the returned slice exists.
    /// This function
    /// may invoke arbitrary foreign code, so no safety guarantees can be made.
    pub unsafe fn as_mut_slice<'a>(&self) -> &'a mut [T] {
        let ptr = self.data_mut();
        let size = self.size();
        slice::from_raw_parts_mut(ptr, size)
    }
}

impl<T, T1, T2> CppBox<T>
where
    T: Begin<Output = CppBox<T1>> + End<Output = CppBox<T2>> + CppDeletable,
    T1: CppDeletable + PartialEq<Ref<T2>> + Increment + Indirection,
    T2: CppDeletable,
{
    /// Returns an iterator over the content of the object,
    /// based on `begin()` and `end()` methods.
    ///
    /// # Safety
    ///
    /// The caller must make sure `self` contains a valid pointer. The content must
    /// not be read or modified through other ways while the returned slice exists.
    /// This function
    /// may invoke arbitrary foreign code, so no safety guarantees can be made.
    pub unsafe fn iter(&self) -> CppIterator<T1, T2> {
        cpp_iter(self.begin(), self.end())
    }
}

impl<T, T1, T2> CppBox<T>
where
    T: BeginMut<Output = CppBox<T1>> + EndMut<Output = CppBox<T2>> + CppDeletable,
    T1: CppDeletable + PartialEq<Ref<T2>> + Increment + Indirection,
    T2: CppDeletable,
{
    /// Returns a mutable iterator over the content of the object,
    /// based on `begin()` and `end()` methods.
    ///
    /// # Safety
    ///
    /// The caller must make sure `self` contains a valid pointer. The content must
    /// not be read or modified through other ways while the returned slice exists.
    /// This function
    /// may invoke arbitrary foreign code, so no safety guarantees can be made.
    pub unsafe fn iter_mut(&self) -> CppIterator<T1, T2> {
        cpp_iter(self.begin_mut(), self.end_mut())
    }
}

/// Allows to call member functions of `T` and its base classes directly on the pointer.
impl<T: CppDeletable> Deref for CppBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { self.0.as_ref() }
    }
}

/// Deletes the stored object using C++'s `delete` operator.
impl<T: CppDeletable> Drop for CppBox<T> {
    fn drop(&mut self) {
        unsafe {
            T::delete(self.0.as_ref());
        }
    }
}

impl<T: CppDeletable> fmt::Debug for CppBox<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "CppBox({:?})", self.0)
    }
}

#[cfg(test)]
mod tests {
    use crate::{CppBox, CppDeletable, Ptr};
    use std::cell::RefCell;
    use std::rc::Rc;

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

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

    impl CppDeletable for Struct1 {
        unsafe fn delete(&self) {
            struct1_delete(self);
        }
    }

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