autocxx::subclass

Trait CppSubclass

Source
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
    // Required methods
    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;
    fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;

    // Provided methods
    fn peer(&self) -> &CppPeer { ... }
    fn peer_mut(&mut self) -> Pin<&mut CppPeer> { ... }
    fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer>  { ... }
    fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> { ... }
}
Expand description

A subclass of a C++ type.

To create a Rust subclass of a C++ class, you must do these things:

§How to access your Rust structure from outside

Use CppSubclass::new_rust_owned then use std::cell::RefCell::borrow or std::cell::RefCell::borrow_mut to obtain the underlying Rust struct.

§How to call C++ methods on the subclass

Do the same. You should find that your subclass struct impls all the C++ methods belonging to the superclass.

§How to implement virtual methods

Simply add an impl for the struct, implementing the relevant method. The C++ virtual function call will be redirected to your Rust implementation.

§How not to implement virtual methods

If you don’t want to implement a virtual method, don’t: the superclass method will be called instead. Naturally, you must implement any pure virtual methods.

§How it works

This actually consists of two objects: this object itself and a C++-side peer. The ownership relationship between those two things can work in three different ways:

  1. Neither object is owned by Rust. The C++ peer is owned by a C++ UniquePtr held elsewhere in C++. That C++ peer then owns this Rust-side object via a strong Rc reference. This is the ownership relationship set up by CppSubclass::new_cpp_owned.
  2. The object pair is owned by Rust. Specifically, by a strong Rc reference to this Rust-side object. In turn, the Rust-side object owns the C++-side peer via a UniquePtr. This is what’s set up by CppSubclass::new_rust_owned. The C++-side peer does not own the Rust object; it just has a weak pointer. (Otherwise we’d get a reference loop and nothing would ever be freed.)
  3. The object pair is self-owned and will stay around forever until CppSubclassSelfOwned::delete_self is called. In this case there’s a strong reference from the C++ to the Rust and from the Rust to the C++. This is useful for cases where the subclass is listening for events, and needs to stick around until a particular event occurs then delete itself.

§Limitations

  • Re-entrancy. The main thing to look out for is re-entrancy. If a (non-const) virtual method is called on your type, which then causes you to call back into C++, which results in a second call into a (non-const) virtual method, we will try to create two mutable references to your subclass which isn’t allowed in Rust and will therefore panic.

    A future version of autocxx may provide the option of treating all non-const methods (in C++) as const methods on the Rust side, which will give the option of using interior mutability (std::cell::RefCell) for you to safely handle this situation, whilst remaining compatible with existing C++ interfaces. If you need this, indicate support on this issue.

  • Thread safety. The subclass object is not thread-safe and shouldn’t be passed to different threads in C++. A future version of this code will give the option to use Arc and Mutex internally rather than Rc and RefCell, solving this problem.

  • Protected methods. We don’t do anything clever here - they’re public.

  • Non-trivial class hierarchies. We don’t yet consider virtual methods on base classes of base classes. This is a temporary limitation, see this issue.

Required Methods§

Source

fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>

Return the field which holds the C++ peer object. This is normally implemented by the #is_subclass macro, but you’re welcome to implement it yourself if you prefer.

Source

fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>

Return the field which holds the C++ peer object. This is normally implemented by the #is_subclass macro, but you’re welcome to implement it yourself if you prefer.

Provided Methods§

Source

fn peer(&self) -> &CppPeer

Return a reference to the C++ part of this object pair. This can be used to register listeners, etc.

Source

fn peer_mut(&mut self) -> Pin<&mut CppPeer>

Return a mutable reference to the C++ part of this object pair. This can be used to register listeners, etc.

Source

fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer>

Creates a new instance of this subclass. This instance is owned by the returned cxx::UniquePtr and thus would typically be returned immediately to C++ such that it can be owned on the C++ side.

Source

fn new_rust_owned(me: Self) -> Rc<RefCell<Self>>

Creates a new instance of this subclass. This instance is not owned by C++, and therefore will be deleted when it goes out of scope in Rust.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§