diff --git a/crates/cxx-qt-gen/src/writer/rust/mod.rs b/crates/cxx-qt-gen/src/writer/rust/mod.rs index 0ffe1b2c6..205776cd1 100644 --- a/crates/cxx-qt-gen/src/writer/rust/mod.rs +++ b/crates/cxx-qt-gen/src/writer/rust/mod.rs @@ -41,9 +41,9 @@ fn cxx_bridge_common_blocks(qobject: &GeneratedRustQObject) -> Vec /// 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 /// @@ -72,12 +72,9 @@ fn cxx_bridge_common_blocks(qobject: &GeneratedRustQObject) -> Vec }, 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! { @@ -137,6 +134,19 @@ fn cxx_qt_common_blocks(qobject: &GeneratedRustQObject) -> Vec { inner: std::boxed::Box) + 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> { @@ -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 = cxx::UniquePtr; @@ -458,9 +469,9 @@ mod tests { /// 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 /// @@ -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" { @@ -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 = cxx::UniquePtr; @@ -549,6 +558,16 @@ mod tests { inner: std::boxed::Box) + 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 { std::default::Default::default() @@ -615,9 +634,9 @@ mod tests { /// 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 /// @@ -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" { @@ -677,9 +693,9 @@ mod tests { /// 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 /// @@ -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" { @@ -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 = cxx::UniquePtr; @@ -768,6 +782,16 @@ mod tests { inner: std::boxed::Box) + 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 { std::default::Default::default() @@ -809,6 +833,16 @@ mod tests { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt-gen/test_outputs/inheritance.rs b/crates/cxx-qt-gen/test_outputs/inheritance.rs index 6f17fc561..70e802c50 100644 --- a/crates/cxx-qt-gen/test_outputs/inheritance.rs +++ b/crates/cxx-qt-gen/test_outputs/inheritance.rs @@ -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" "] 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."] @@ -95,12 +95,9 @@ mod inheritance { fn newCppObject() -> UniquePtr; } 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"] @@ -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 = cxx::UniquePtr; @@ -194,6 +192,15 @@ mod cxx_qt_inheritance { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt-gen/test_outputs/invokables.rs b/crates/cxx-qt-gen/test_outputs/invokables.rs index 3da54620b..407774db9 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -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" "] 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."] @@ -113,12 +113,9 @@ mod ffi { fn newCppObject() -> UniquePtr; } 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"] @@ -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 = cxx::UniquePtr; @@ -287,6 +285,15 @@ mod cxx_qt_ffi { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs index 0535bd958..a0f9789e9 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough_and_naming.rs @@ -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" "] 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."] @@ -145,12 +145,9 @@ pub mod ffi { fn newCppObject() -> UniquePtr; } 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"] @@ -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" "] 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."] @@ -243,12 +240,9 @@ pub mod ffi { fn newCppObject() -> UniquePtr; } 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"] @@ -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 = cxx::UniquePtr; @@ -405,6 +400,15 @@ mod cxx_qt_ffi { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() @@ -527,6 +531,15 @@ mod cxx_qt_ffi { pub struct SecondObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt-gen/test_outputs/properties.rs b/crates/cxx-qt-gen/test_outputs/properties.rs index 1e4a47494..63f24dbee 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -80,9 +80,9 @@ mod ffi { #[doc = r" For now we use a type alias in C++ then use it like a normal type here"] #[doc = r" "] 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."] @@ -103,12 +103,9 @@ mod ffi { fn newCppObject() -> UniquePtr; } 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"] @@ -121,6 +118,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 = cxx::UniquePtr; @@ -297,6 +295,15 @@ mod cxx_qt_ffi { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt-gen/test_outputs/signals.rs b/crates/cxx-qt-gen/test_outputs/signals.rs index c2eee9226..ce79f7566 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -123,9 +123,9 @@ mod ffi { #[doc = r" For now we use a type alias in C++ then use it like a normal type here"] #[doc = r" "] 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."] @@ -146,12 +146,9 @@ mod ffi { fn newCppObject() -> UniquePtr; } 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"] @@ -164,6 +161,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 = cxx::UniquePtr; @@ -309,6 +307,15 @@ mod cxx_qt_ffi { pub struct MyObjectCxxQtThreadQueuedFn { inner: std::boxed::Box) + 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 { std::default::Default::default() diff --git a/crates/cxx-qt/src/lib.rs b/crates/cxx-qt/src/lib.rs index d009938ed..99d316379 100644 --- a/crates/cxx-qt/src/lib.rs +++ b/crates/cxx-qt/src/lib.rs @@ -13,3 +13,21 @@ pub use cxx_qt_macro::bridge; pub use cxx_qt_macro::inherit; pub use cxx_qt_macro::qobject; pub use cxx_qt_macro::qsignals; + +/// This trait is automatically implemented for all types which are marked as `#[cxx_qt::qobject]`. +/// It provides information about the type that is wrapped by the QObject, as well as the methods +/// that Cxx-Qt will generate for the QObject. +pub trait CxxQtType { + /// The Rust type that this QObject is wrapping. + type Rust; + + /// Retrieve an immutable reference to the Rust struct backing this C++ object + fn rust(&self) -> &Self::Rust; + + /// Retrieve a mutable reference to the Rust struct backing this C++ object + /// + /// # Safety + /// 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. + unsafe fn rust_mut(self: core::pin::Pin<&mut Self>) -> core::pin::Pin<&mut Self::Rust>; +}