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.

Implementors§