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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
use crate::ops::{Begin, BeginMut, End, EndMut};
use crate::{DynamicCast, MutPtr, MutRef, Ptr, Ref, StaticDowncast, StaticUpcast};
use std::ops::{Deref, DerefMut};
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`.
    unsafe fn delete(&mut 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` and `DerefMut`, 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 `MutPtr`.
    ///
    /// 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: MutPtr<T>) -> Option<Self> {
        Self::from_raw(ptr.as_mut_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: *mut T) -> Option<Self> {
        ptr::NonNull::new(ptr).map(CppBox)
    }
}

impl<T: CppDeletable> CppBox<T> {
    /// 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 mutable pointer to the value in the box.
    ///
    /// ### Safety
    ///
    /// This operation is safe as long as `self` is valid.
    pub unsafe fn as_mut_ptr(&mut self) -> MutPtr<T> {
        MutPtr::from_raw(self.0.as_ptr())
    }

    /// Returns a constant raw pointer to the value in the box.
    pub fn as_mut_raw_ptr(&mut 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) -> MutPtr<T> {
        let ptr = MutPtr::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 mutable 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_mut_ref(&mut self) -> MutRef<T> {
        MutRef::from_raw_non_null(self.0)
    }

    /// 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()
    }

    /// 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_mut<U>(&mut self) -> MutRef<U>
    where
        T: StaticUpcast<U>,
    {
        StaticUpcast::static_upcast_mut(self.as_mut_ptr())
            .as_mut_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_mut<U>(&mut self) -> MutRef<U>
    where
        T: StaticDowncast<U>,
    {
        StaticDowncast::static_downcast_mut(self.as_mut_ptr())
            .as_mut_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_mut<U>(&mut self) -> Option<MutRef<U>>
    where
        T: DynamicCast<U>,
    {
        DynamicCast::dynamic_cast_mut(self.as_mut_ptr()).as_mut_ref()
    }

    /// Returns a C++ const iterator object pointing to the beginning of the collection.
    ///
    /// It's recommended to iterate directly on a `&CppBox<T>` when possible, using automatic
    /// `IntoIterator` implementation.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code.
    pub unsafe fn begin(&self) -> <&'static T as Begin>::Output
    where
        &'static T: Begin,
    {
        (*self.as_raw_ptr()).begin()
    }

    /// Returns a C++ mutable iterator object pointing to the beginning of the collection.
    ///
    /// It's recommended to iterate directly on a `&mut CppBox<T>` when possible, using automatic
    /// `IntoIterator` implementation.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code.
    pub unsafe fn begin_mut(&mut self) -> <&'static mut T as BeginMut>::Output
    where
        &'static mut T: BeginMut,
    {
        (*self.as_mut_raw_ptr()).begin_mut()
    }

    /// Returns a C++ const iterator object pointing to the end of the collection.
    ///
    /// It's recommended to iterate directly on a `&CppBox<T>` when possible, using automatic
    /// `IntoIterator` implementation.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code.
    pub unsafe fn end(&self) -> <&'static T as End>::Output
    where
        &'static T: End,
    {
        (*self.as_raw_ptr()).end()
    }

    /// Returns a C++ mutable iterator object pointing to the end of the collection.
    ///
    /// It's recommended to iterate directly on a `&mut CppBox<T>` when possible, using automatic
    /// `IntoIterator` implementation.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code.
    pub unsafe fn end_mut(&mut self) -> <&'static mut T as EndMut>::Output
    where
        &'static mut T: EndMut,
    {
        (*self.as_mut_raw_ptr()).end_mut()
    }

    /// Returns a slice corresponding to the object. This function is available when `begin()` and
    /// `end()` functions of the object return pointers.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code. It's not recommended to store the slice
    /// because it may be modified by the C++ library, which would violate Rust's aliasing rules.
    pub unsafe fn as_slice<'a, T1>(&'a self) -> &'a [T1]
    where
        T: 'static,
        &'static T: Begin<Output = Ptr<T1>> + End<Output = Ptr<T1>>,
    {
        let begin = self.begin().as_raw_ptr();
        let end = self.end().as_raw_ptr();
        let count = (end as usize).saturating_sub(begin as usize) / mem::size_of::<T1>();
        slice::from_raw_parts(begin, count)
    }

    /// Returns a mutable slice corresponding to the object.
    /// This function is available when `begin()` and
    /// `end()` functions of the object return pointers.
    ///
    /// ### Safety
    ///
    /// `self` must be valid. It's not possible to make any guarantees about safety, since
    /// this function calls arbitrary C++ library code. It's not recommended to store the slice
    /// because it may be modified by the C++ library, which would violate Rust's aliasing rules.
    pub unsafe fn as_mut_slice<'a, T1>(&'a mut self) -> &'a mut [T1]
    where
        T: 'static,
        &'static mut T: BeginMut<Output = MutPtr<T1>> + EndMut<Output = MutPtr<T1>>,
    {
        let begin = self.begin_mut().as_mut_raw_ptr();
        let end = self.end_mut().as_mut_raw_ptr();
        let count = (end as usize).saturating_sub(begin as usize) / mem::size_of::<T1>();
        slice::from_raw_parts_mut(begin, count)
    }
}

/// 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() }
    }
}

/// Allows to call member functions of `T` and its base classes directly on the pointer.
impl<T: CppDeletable> DerefMut for CppBox<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { self.0.as_mut() }
    }
}

/// 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_mut());
        }
    }
}

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, MutPtr};
    use std::cell::RefCell;
    use std::rc::Rc;

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

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

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

    #[test]
    fn test_drop_calls_deleter() {
        let value1 = Rc::new(RefCell::new(10));
        let mut object1 = Struct1 {
            value: value1.clone(),
        };
        assert!(*value1.borrow() == 10);
        unsafe {
            // TODO: remove all "as *mut _" because it's automatic
            CppBox::new(MutPtr::from_raw(&mut object1));
        }
        assert!(*value1.borrow() == 42);
    }
}