Skip to content

Commit

Permalink
cxx-qt: Add CxxQtType trait.
Browse files Browse the repository at this point in the history
Allows the type system to reason about the inner type of a given CXX-Qt
QObject.
Also cleanly documents where `rust` and `rust_mut` come from.
  • Loading branch information
LeonMatthesKDAB committed May 30, 2023
1 parent 4de28a3 commit 2a8356c
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 70 deletions.
90 changes: 62 additions & 28 deletions crates/cxx-qt-gen/src/writer/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ fn cxx_bridge_common_blocks(qobject: &GeneratedRustQObject) -> Vec<TokenStream>
/// <https://github.com/dtolnay/cxx/issues/683>
type #cxx_qt_thread_ident;

/// Retrieve an immutable reference to the Rust struct backing this C++ object
#[cxx_name = "unsafeRust"]
fn rust(self: &#cpp_struct_ident) -> &#rust_struct_ident;
#[doc(hidden)]
fn ffi_rust(self: &#cpp_struct_ident) -> &#rust_struct_ident;

/// Create an instance of a CxxQtThread
///
Expand Down Expand Up @@ -72,12 +72,9 @@ fn cxx_bridge_common_blocks(qobject: &GeneratedRustQObject) -> Vec<TokenStream>
},
quote! {
extern "C++" {
/// Retrieve a mutable reference to the Rust struct backing this C++ object
///
/// This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal.
/// The property changed signal must be emitted manually.
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut #cpp_struct_ident>) -> Pin<&mut #rust_struct_ident>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut #cpp_struct_ident>) -> Pin<&mut #rust_struct_ident>;
}
},
quote! {
Expand Down Expand Up @@ -137,6 +134,19 @@ fn cxx_qt_common_blocks(qobject: &GeneratedRustQObject) -> Vec<TokenStream> {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut #cpp_struct_ident>) + Send>,
}
},
quote! {
impl cxx_qt::CxxQtType for #cpp_struct_ident {
type Rust = #rust_struct_ident;

fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}

unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}
},
quote! {
/// Generated CXX-Qt method which creates a boxed rust struct of a QObject
pub fn #create_rs_ident() -> std::boxed::Box<#rust_struct_ident> {
Expand Down Expand Up @@ -248,6 +258,7 @@ pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream {
mod #cxx_qt_mod_ident {
use super::#cxx_mod_ident::*;
use std::pin::Pin;
use cxx_qt::CxxQtType;

#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -458,9 +469,9 @@ mod tests {
/// <https://github.com/dtolnay/cxx/issues/683>
type MyObjectCxxQtThread;

/// Retrieve an immutable reference to the Rust struct backing this C++ object
#[cxx_name = "unsafeRust"]
fn rust(self: &MyObjectQt) -> &MyObject;
#[doc(hidden)]
fn ffi_rust(self: &MyObjectQt) -> &MyObject;

/// Create an instance of a CxxQtThread
///
Expand All @@ -485,12 +496,9 @@ mod tests {
}

extern "C++" {
/// Retrieve a mutable reference to the Rust struct backing this C++ object
///
/// This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal.
/// The property changed signal must be emitted manually.
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
}

extern "Rust" {
Expand All @@ -507,6 +515,7 @@ mod tests {
mod cxx_qt_ffi {
use super::ffi::*;
use std::pin::Pin;
use cxx_qt::CxxQtType;

#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -549,6 +558,16 @@ mod tests {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut MyObjectQt>) + Send>,
}

impl cxx_qt::CxxQtType for MyObjectQt {
type Rust = MyObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}

/// Generated CXX-Qt method which creates a boxed rust struct of a QObject
pub fn create_rs_my_object() -> std::boxed::Box<MyObject> {
std::default::Default::default()
Expand Down Expand Up @@ -615,9 +634,9 @@ mod tests {
/// <https://github.com/dtolnay/cxx/issues/683>
type FirstObjectCxxQtThread;

/// Retrieve an immutable reference to the Rust struct backing this C++ object
#[cxx_name = "unsafeRust"]
fn rust(self: &FirstObjectQt) -> &FirstObject;
#[doc(hidden)]
fn ffi_rust(self: &FirstObjectQt) -> &FirstObject;

/// Create an instance of a CxxQtThread
///
Expand All @@ -642,12 +661,9 @@ mod tests {
}

extern "C++" {
/// Retrieve a mutable reference to the Rust struct backing this C++ object
///
/// This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal.
/// The property changed signal must be emitted manually.
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut FirstObjectQt>) -> Pin<&mut FirstObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut FirstObjectQt>) -> Pin<&mut FirstObject>;
}

extern "Rust" {
Expand Down Expand Up @@ -677,9 +693,9 @@ mod tests {
/// <https://github.com/dtolnay/cxx/issues/683>
type SecondObjectCxxQtThread;

/// Retrieve an immutable reference to the Rust struct backing this C++ object
#[cxx_name = "unsafeRust"]
fn rust(self: &SecondObjectQt) -> &SecondObject;
#[doc(hidden)]
fn ffi_rust(self: &SecondObjectQt) -> &SecondObject;

/// Create an instance of a CxxQtThread
///
Expand All @@ -704,12 +720,9 @@ mod tests {
}

extern "C++" {
/// Retrieve a mutable reference to the Rust struct backing this C++ object
///
/// This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal.
/// The property changed signal must be emitted manually.
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut SecondObjectQt>) -> Pin<&mut SecondObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut SecondObjectQt>) -> Pin<&mut SecondObject>;
}

extern "Rust" {
Expand All @@ -726,6 +739,7 @@ mod tests {
mod cxx_qt_ffi {
use super::ffi::*;
use std::pin::Pin;
use cxx_qt::CxxQtType;

#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -768,6 +782,16 @@ mod tests {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut FirstObjectQt>) + Send>,
}

impl cxx_qt::CxxQtType for FirstObjectQt {
type Rust = FirstObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}

/// Generated CXX-Qt method which creates a boxed rust struct of a QObject
pub fn create_rs_first_object() -> std::boxed::Box<FirstObject> {
std::default::Default::default()
Expand Down Expand Up @@ -809,6 +833,16 @@ mod tests {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut SecondObjectQt>) + Send>,
}

impl cxx_qt::CxxQtType for SecondObjectQt {
type Rust = SecondObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}

/// Generated CXX-Qt method which creates a boxed rust struct of a QObject
pub fn create_rs_second_object() -> std::boxed::Box<SecondObject> {
std::default::Default::default()
Expand Down
21 changes: 14 additions & 7 deletions crates/cxx-qt-gen/test_outputs/inheritance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ mod inheritance {
#[doc = r" For now we use a type alias in C++ then use it like a normal type here"]
#[doc = r" <https://github.com/dtolnay/cxx/issues/683>"]
type MyObjectCxxQtThread;
#[doc = r" Retrieve an immutable reference to the Rust struct backing this C++ object"]
#[cxx_name = "unsafeRust"]
fn rust(self: &MyObjectQt) -> &MyObject;
#[doc(hidden)]
fn ffi_rust(self: &MyObjectQt) -> &MyObject;
#[doc = r" Create an instance of a CxxQtThread"]
#[doc = r""]
#[doc = r" This allows for queueing closures onto the Qt event loop from a background thread."]
Expand All @@ -95,12 +95,9 @@ mod inheritance {
fn newCppObject() -> UniquePtr<MyObjectQt>;
}
extern "C++" {
#[doc = r" Retrieve a mutable reference to the Rust struct backing this C++ object"]
#[doc = r""]
#[doc = r" This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal."]
#[doc = r" The property changed signal must be emitted manually."]
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
}
extern "Rust" {
#[namespace = "cxx_qt_my_object"]
Expand All @@ -113,6 +110,7 @@ mod inheritance {
use self::cxx_qt_inheritance::*;
mod cxx_qt_inheritance {
use super::inheritance::*;
use cxx_qt::CxxQtType;
use std::pin::Pin;
#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -194,6 +192,15 @@ mod cxx_qt_inheritance {
pub struct MyObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut MyObjectQt>) + Send>,
}
impl cxx_qt::CxxQtType for MyObjectQt {
type Rust = MyObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}
#[doc = r" Generated CXX-Qt method which creates a boxed rust struct of a QObject"]
pub fn create_rs_my_object() -> std::boxed::Box<MyObject> {
std::default::Default::default()
Expand Down
21 changes: 14 additions & 7 deletions crates/cxx-qt-gen/test_outputs/invokables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ mod ffi {
#[doc = r" For now we use a type alias in C++ then use it like a normal type here"]
#[doc = r" <https://github.com/dtolnay/cxx/issues/683>"]
type MyObjectCxxQtThread;
#[doc = r" Retrieve an immutable reference to the Rust struct backing this C++ object"]
#[cxx_name = "unsafeRust"]
fn rust(self: &MyObjectQt) -> &MyObject;
#[doc(hidden)]
fn ffi_rust(self: &MyObjectQt) -> &MyObject;
#[doc = r" Create an instance of a CxxQtThread"]
#[doc = r""]
#[doc = r" This allows for queueing closures onto the Qt event loop from a background thread."]
Expand All @@ -113,12 +113,9 @@ mod ffi {
fn newCppObject() -> UniquePtr<MyObjectQt>;
}
extern "C++" {
#[doc = r" Retrieve a mutable reference to the Rust struct backing this C++ object"]
#[doc = r""]
#[doc = r" This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal."]
#[doc = r" The property changed signal must be emitted manually."]
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
}
extern "Rust" {
#[namespace = "cxx_qt::my_object::cxx_qt_my_object"]
Expand All @@ -131,6 +128,7 @@ mod ffi {
use self::cxx_qt_ffi::*;
mod cxx_qt_ffi {
use super::ffi::*;
use cxx_qt::CxxQtType;
use std::pin::Pin;
#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -287,6 +285,15 @@ mod cxx_qt_ffi {
pub struct MyObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut MyObjectQt>) + Send>,
}
impl cxx_qt::CxxQtType for MyObjectQt {
type Rust = MyObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}
#[doc = r" Generated CXX-Qt method which creates a boxed rust struct of a QObject"]
pub fn create_rs_my_object() -> std::boxed::Box<MyObject> {
std::default::Default::default()
Expand Down
41 changes: 27 additions & 14 deletions crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ pub mod ffi {
#[doc = r" For now we use a type alias in C++ then use it like a normal type here"]
#[doc = r" <https://github.com/dtolnay/cxx/issues/683>"]
type MyObjectCxxQtThread;
#[doc = r" Retrieve an immutable reference to the Rust struct backing this C++ object"]
#[cxx_name = "unsafeRust"]
fn rust(self: &MyObjectQt) -> &MyObject;
#[doc(hidden)]
fn ffi_rust(self: &MyObjectQt) -> &MyObject;
#[doc = r" Create an instance of a CxxQtThread"]
#[doc = r""]
#[doc = r" This allows for queueing closures onto the Qt event loop from a background thread."]
Expand All @@ -145,12 +145,9 @@ pub mod ffi {
fn newCppObject() -> UniquePtr<MyObjectQt>;
}
extern "C++" {
#[doc = r" Retrieve a mutable reference to the Rust struct backing this C++ object"]
#[doc = r""]
#[doc = r" This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal."]
#[doc = r" The property changed signal must be emitted manually."]
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut MyObjectQt>) -> Pin<&mut MyObject>;
}
extern "Rust" {
#[namespace = "cxx_qt::multi_object::cxx_qt_my_object"]
Expand Down Expand Up @@ -220,9 +217,9 @@ pub mod ffi {
#[doc = r" For now we use a type alias in C++ then use it like a normal type here"]
#[doc = r" <https://github.com/dtolnay/cxx/issues/683>"]
type SecondObjectCxxQtThread;
#[doc = r" Retrieve an immutable reference to the Rust struct backing this C++ object"]
#[cxx_name = "unsafeRust"]
fn rust(self: &SecondObjectQt) -> &SecondObject;
#[doc(hidden)]
fn ffi_rust(self: &SecondObjectQt) -> &SecondObject;
#[doc = r" Create an instance of a CxxQtThread"]
#[doc = r""]
#[doc = r" This allows for queueing closures onto the Qt event loop from a background thread."]
Expand All @@ -243,12 +240,9 @@ pub mod ffi {
fn newCppObject() -> UniquePtr<SecondObjectQt>;
}
extern "C++" {
#[doc = r" Retrieve a mutable reference to the Rust struct backing this C++ object"]
#[doc = r""]
#[doc = r" This method is unsafe because it allows a Q_PROPERTY to be modified without emitting its changed signal."]
#[doc = r" The property changed signal must be emitted manually."]
#[cxx_name = "unsafeRustMut"]
unsafe fn rust_mut(self: Pin<&mut SecondObjectQt>) -> Pin<&mut SecondObject>;
#[doc(hidden)]
unsafe fn ffi_rust_mut(self: Pin<&mut SecondObjectQt>) -> Pin<&mut SecondObject>;
}
extern "Rust" {
#[namespace = "cxx_qt::multi_object::cxx_qt_second_object"]
Expand All @@ -261,6 +255,7 @@ pub mod ffi {
pub use self::cxx_qt_ffi::*;
mod cxx_qt_ffi {
use super::ffi::*;
use cxx_qt::CxxQtType;
use std::pin::Pin;
#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
Expand Down Expand Up @@ -405,6 +400,15 @@ mod cxx_qt_ffi {
pub struct MyObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut MyObjectQt>) + Send>,
}
impl cxx_qt::CxxQtType for MyObjectQt {
type Rust = MyObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}
#[doc = r" Generated CXX-Qt method which creates a boxed rust struct of a QObject"]
pub fn create_rs_my_object() -> std::boxed::Box<MyObject> {
std::default::Default::default()
Expand Down Expand Up @@ -527,6 +531,15 @@ mod cxx_qt_ffi {
pub struct SecondObjectCxxQtThreadQueuedFn {
inner: std::boxed::Box<dyn FnOnce(std::pin::Pin<&mut SecondObjectQt>) + Send>,
}
impl cxx_qt::CxxQtType for SecondObjectQt {
type Rust = SecondObject;
fn rust(&self) -> &Self::Rust {
self.ffi_rust()
}
unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> Pin<&mut Self::Rust> {
self.ffi_rust_mut()
}
}
#[doc = r" Generated CXX-Qt method which creates a boxed rust struct of a QObject"]
pub fn create_rs_second_object() -> std::boxed::Box<SecondObject> {
std::default::Default::default()
Expand Down
Loading

0 comments on commit 2a8356c

Please sign in to comment.