Expand description
§Qt Interfaces (Internal Documentation)
This crate provides proxies for various Qt (C++) interfaces using Cxx. Proxies serve as the bridge between Rust and C++ implementations of Qt interfaces, allowing Rust types to implement behavior expected by C++ code and to access C++ functionality from Rust.
§The proxy
Each Qt interface has a corresponding proxy in Rust. This proxy has
to implement the qtbridge_runtime::qproxies::QRustProxy trait and interacts mostly with
the qtbridge_runtime::QObjectHolder trait, that is automatically implemented for all
user types by the qobject macro.
The demands on proxies are baked into the qtbridge_runtime::qproxies::QRustProxy trait.
For example, there
is the demand to provide a Qt static meta object, usually from the “base” this proxy
is derived from. Further, the proxy has to provide a marker trait called AdapterType
that is at a minimum used to store a reference to the user object as
Rc<RefCell<dyn AdapterType>>. Otherwise the proxy is mostly free in its design.
All proxies provided in this module follow a similar architecture. The proxy works together with a set of traits. The QObject proxy is very different since it is the proxy that is used if only QMetaObject functionality needs to be provided but no interface implementation.
§Traits
- User-implemented functionality: Rust implementations of Qt virtual functions.
- Rust access to C++ functionality: Rust wrappers around C++ methods of the interface.
- Internal type erasure and proxy plumbing: Allows dynamic behavior when types are not fully known at compile time.
These proxies rely on the following Rust traits to define functionality and structure,
shown on the example of QListModel.
§1. QListModel
- Responsibility: Must be implemented by the user.
- Purpose: Functions in this trait are called from C++ via the proxy, providing Rust implementations of Qt virtual functions. Some modifications can be done in the functions to shape the API and to erase Qt types (e.g. QVariant and QModelIndex).
- Associated Types: Defines types (e.g.,
Item) that are part of the interface contract. - Notes: Users implement function as expected from the Qt API. Default implementation can exist for non-pure virtual functions.
§2. QListModelBase
- Responsibility: Default / blank implementation for all
QListModel. - Purpose: Provides access to C++ functions from Rust and other convenience functions that should not be overridden. Serves as a bridge between user logic and C++ functionality. Functions that should not be overridden by the user are implemented here.
- Notes: This trait forms the core Rust interface to call C++ functions for types implementing
QListModel.
§3. QListModelAdapter (Internal Only)
- Responsibility: Default / blank implementation for all
QListModel. - Purpose: Provides a type-erased interface for internal machinery. Traits with associated
types (like
QListModel::Item) cannot be used asdyntraits in Rust.QListModelAdaptererases unknown types while exposing the necessary interface internally. - Notes: Never meant for user implementation or usage. Facilitates dynamic behavior and internal bridging without exposing associated types to user code.
§Memory Ownership and Lifetimes
Every instance of a user-defined Rust struct annotated with #[qobject]
has two auxiliary parts invisible to the user:
CppProxy- a C++ class derived fromQObjectorQAbstractItemModel(or another base interface). This is the object the QML engine sees and interacts with. It is allocated with a regularnewfor Rust-created objects, or with placementnewat a QML-engine-supplied address for QML-created elements.RustProxy- the Rust-side bridge, heap-allocated viaBox::into_rawinQRustProxy::new. It holds a pointer toCppProxyand a reference the user struct asRc<RefCell<UserStruct>>orWeak<RefCell<UserStruct>>inRustObjAccess.
The CppProxy C++ destructor is the common teardown point for the proxy pair: it always
calls GenericRustProxy::drop_self, which fires the on_drop callback and then drops
RustProxy along with its Rc/Weak reference to the user struct.
§Who destroys CppProxy?
That depends on who owns the object, determined at construction by ConstructionMode.
§QML-created objects
RustProxy holds a strong Rc<RefCell<UserStruct>> (SharedReferenceWithQml::OwnedByQml).
JS GC deletes QObject
→ virtual ~CppProxy()
→ GenericRustProxy::drop_self
→ on_drop() fires
→ Rc<RefCell<UserStruct>> strong count −1
→ UserStruct::drop() (only if this was the last strong Rc)§Rust-created objects
RustProxy holds only a Weak<RefCell<UserStruct>>
(SharedReferenceWithQml::OwnedByRust). The Rust Rc controls the struct’s lifetime.
When the last strong Rc is dropped, QObjectHolder::detach_qobject deletes CppProxy.
Last strong Rc<RefCell<UserStruct>> dropped on the Rust side
→ UserStruct::drop()
→ QObjectHolder::detach_qobject()
→ virtual ~CppProxy()
→ GenericRustProxy::drop_self
→ on_drop()Re-exports§
pub use qabstract_item_model::QAbstractItemModel;pub use qabstract_item_model::QAbstractItemModelBase;pub use qlist_model::QListModel;pub use qlist_model::QListModelBase;pub use qparser_status::QParserStatus;pub use qtable_model::QTableModel;pub use qtable_model::QTableModelBase;pub use object_access::rust_object_access::RustObjAccess;