macro_rules! cpp_class {
($(#[$($attrs:tt)*])* unsafe struct $name:ident as $type:expr) => { ... };
($(#[$($attrs:tt)*])* pub unsafe struct $name:ident as $type:expr) => { ... };
($(#[$($attrs:tt)*])* pub($($pub:tt)*) unsafe struct $name:ident as $type:expr) => { ... };
}
Expand description
This macro allows wrapping a relocatable C++ struct or class that might have
a destructor or copy constructor, implementing the Drop
and Clone
trait
appropriately.
cpp_class!(pub unsafe struct MyClass as "MyClass");
impl MyClass {
fn new() -> Self {
unsafe { cpp!([] -> MyClass as "MyClass" { return MyClass(); }) }
}
fn member_function(&self, param : i32) -> i32 {
unsafe { cpp!([self as "const MyClass*", param as "int"] -> i32 as "int" {
return self->member_function(param);
}) }
}
}
This will create a Rust struct MyClass
, which has the same size and
alignment as the C++ class MyClass
. It will also implement the Drop
trait
calling the destructor, the Clone
trait calling the copy constructor, if the
class is copyable (or Copy
if it is trivially copyable), and Default
if the class
is default constructible
§Derived Traits
The Default
, Clone
and Copy
traits are implicitly implemented if the C++
type has the corresponding constructors.
You can add the #[derive(...)]
attribute in the macro in order to get automatic
implementation of the following traits:
- The trait
PartialEq
will call the C++operator==
. - You can add the trait
Eq
if the semantics of the C++ operator are those ofEq
- The trait
PartialOrd
need the C++operator<
for that type.lt
,le
,gt
andge
will use the corresponding C++ operator if it is defined, otherwise it will fallback to the less than operator. For PartialOrd::partial_cmp, theoperator<
will be called twice. Note that it will never returnNone
. - The trait
Ord
can also be specified when the semantics of theoperator<
corresponds to a total order
§Safety Warning
Use of this macro is highly unsafe. Only certain C++ classes can be bound to, C++ classes may perform arbitrary unsafe operations, and invariants are easy to break.
A notable restriction is that this macro only works if the C++ class is relocatable.
§Relocatable classes
In order to be able to we wrapped the C++ class must be relocatable. That means
that it can be moved in memory using memcpy
. This restriction exists because
safe Rust is allowed to move your types around.
Most C++ types which do not contain self-references will be compatible,
although this property cannot be statically checked by rust-cpp
.
All types that satisfy std::is_trivially_copyable
are compatible.
Maybe future version of the C++ standard would allow a compile-time check:
P1144
Unfortunately, as the STL often uses internal self-references for
optimization purposes, such as the small-string optimization, this disallows
most std:: classes.
But std::unique_ptr<T>
and std::shared_ptr<T>
works.