Skip to content

Commit

Permalink
cxx-qt-gen: add a method to fully qualify CXX bridge args
Browse files Browse the repository at this point in the history
Related to KDAB#404
  • Loading branch information
ahayzen-kdab authored and Be-ing committed Jul 24, 2023
1 parent f2cc916 commit e3013b1
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 28 deletions.
8 changes: 5 additions & 3 deletions crates/cxx-qt-gen/src/generator/rust/property/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,35 @@
use crate::generator::{
naming::{property::QPropertyName, qobject::QObjectName},
rust::fragment::RustFragmentPair,
utils::rust::syn_type_cxx_bridge_to_qualified,
};
use quote::quote;
use syn::Type;

pub fn generate(
idents: &QPropertyName,
qobject_idents: &QObjectName,
ty: &Type,
cxx_ty: &Type,
) -> RustFragmentPair {
let cpp_class_name_rust = &qobject_idents.cpp_class.rust;
let getter_wrapper_cpp = idents.getter_wrapper.cpp.to_string();
let getter_rust = &idents.getter.rust;
let ident = &idents.name.rust;
let ident_str = ident.to_string();
let qualified_ty = syn_type_cxx_bridge_to_qualified(cxx_ty);

RustFragmentPair {
cxx_bridge: vec![quote! {
extern "Rust" {
#[cxx_name = #getter_wrapper_cpp]
unsafe fn #getter_rust<'a>(self: &'a #cpp_class_name_rust) -> &'a #ty;
unsafe fn #getter_rust<'a>(self: &'a #cpp_class_name_rust) -> &'a #cxx_ty;
}
}],
implementation: vec![quote! {
impl #cpp_class_name_rust {
#[doc = "Getter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #getter_rust(&self) -> &#ty {
pub fn #getter_rust(&self) -> &#qualified_ty {
&self.#ident
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/property/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ mod tests {
impl MyObject {
#[doc = "Getter for the Q_PROPERTY "]
#[doc = "opaque_property"]
pub fn opaque_property(&self) -> &UniquePtr<QColor> {
pub fn opaque_property(&self) -> &cxx::UniquePtr<QColor> {
&self.opaque_property
}
}
Expand All @@ -180,7 +180,7 @@ mod tests {
impl MyObject {
#[doc = "Setter for the Q_PROPERTY "]
#[doc = "opaque_property"]
pub fn set_opaque_property(mut self: core::pin::Pin<&mut Self>, value: UniquePtr<QColor>) {
pub fn set_opaque_property(mut self: core::pin::Pin<&mut Self>, value: cxx::UniquePtr<QColor>) {
if self.opaque_property == value {
return;
}
Expand Down
11 changes: 6 additions & 5 deletions crates/cxx-qt-gen/src/generator/rust/property/setter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@
use crate::generator::{
naming::{property::QPropertyName, qobject::QObjectName},
rust::fragment::RustFragmentPair,
utils::rust::syn_type_is_cxx_bridge_unsafe,
utils::rust::{syn_type_cxx_bridge_to_qualified, syn_type_is_cxx_bridge_unsafe},
};
use quote::quote;
use syn::Type;

pub fn generate(
idents: &QPropertyName,
qobject_idents: &QObjectName,
ty: &Type,
cxx_ty: &Type,
) -> RustFragmentPair {
let cpp_class_name_rust = &qobject_idents.cpp_class.rust;
let setter_wrapper_cpp = idents.setter_wrapper.cpp.to_string();
let setter_rust = &idents.setter.rust;
let ident = &idents.name.rust;
let ident_str = ident.to_string();
let notify_ident = &idents.notify.rust;
let qualified_ty = syn_type_cxx_bridge_to_qualified(cxx_ty);

// Determine if unsafe is required due to an unsafe type
let has_unsafe = if syn_type_is_cxx_bridge_unsafe(ty) {
let has_unsafe = if syn_type_is_cxx_bridge_unsafe(cxx_ty) {
quote! { unsafe }
} else {
quote! {}
Expand All @@ -34,14 +35,14 @@ pub fn generate(
cxx_bridge: vec![quote! {
extern "Rust" {
#[cxx_name = #setter_wrapper_cpp]
#has_unsafe fn #setter_rust(self: Pin<&mut #cpp_class_name_rust>, value: #ty);
#has_unsafe fn #setter_rust(self: Pin<&mut #cpp_class_name_rust>, value: #cxx_ty);
}
}],
implementation: vec![quote! {
impl #cpp_class_name_rust {
#[doc = "Setter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #setter_rust(mut self: core::pin::Pin<&mut Self>, value: #ty) {
pub fn #setter_rust(mut self: core::pin::Pin<&mut Self>, value: #qualified_ty) {
if self.#ident == value {
// don't want to set the value again and reemit the signal,
// as this can cause binding loops
Expand Down
38 changes: 23 additions & 15 deletions crates/cxx-qt-gen/src/generator/rust/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use crate::{
generator::{
naming::{qobject::QObjectName, signals::QSignalName},
rust::{fragment::RustFragmentPair, qobject::GeneratedRustQObjectBlocks},
utils::rust::syn_type_cxx_bridge_to_qualified,
},
parser::signals::ParsedSignal,
};
use proc_macro2::TokenStream;
use quote::quote;
use syn::Result;
use syn::{parse_quote, FnArg, Result};

pub fn generate_rust_signals(
signals: &Vec<ParsedSignal>,
Expand All @@ -33,24 +33,32 @@ pub fn generate_rust_signals(
let connect_ident_rust_str = connect_ident_rust.to_string();
let on_ident_rust = idents.on_name;

let parameters = signal
let parameters_cxx: Vec<FnArg> = signal
.parameters
.iter()
.map(|parameter| {
let ident = &parameter.ident;
let ty = &parameter.ty;
quote! { #ident: #ty }
parse_quote! { #ident: #ty }
})
.collect::<Vec<TokenStream>>();
.collect();
let parameters_qualified: Vec<FnArg> = parameters_cxx
.iter()
.cloned()
.map(|mut parameter| {
if let FnArg::Typed(pat_type) = &mut parameter {
*pat_type.ty = syn_type_cxx_bridge_to_qualified(&pat_type.ty);
}
parameter
})
.collect();

let (self_type, self_type_cxx) = if signal.mutable {
(
quote! { core::pin::Pin<&mut #qobject_name> },
quote! { Pin<&mut #qobject_name> },
)
let self_type_cxx = if signal.mutable {
parse_quote! { Pin<&mut #qobject_name> }
} else {
(quote! { &#qobject_name }, quote! { &#qobject_name })
parse_quote! { &#qobject_name }
};
let self_type_qualified = syn_type_cxx_bridge_to_qualified(&self_type_cxx);

let mut unsafe_block = None;
let mut unsafe_call = Some(quote! { unsafe });
Expand All @@ -66,7 +74,7 @@ pub fn generate_rust_signals(
#unsafe_block extern "C++" {
#(#attrs)*
#[rust_name = #signal_name_rust_str]
#unsafe_call fn #signal_name_cpp(self: #self_type_cxx, #(#parameters),*);
#unsafe_call fn #signal_name_cpp(self: #self_type_cxx, #(#parameters_cxx),*);
}
},
quote! {
Expand All @@ -76,7 +84,7 @@ pub fn generate_rust_signals(
#[doc = ", so that when the signal is emitted the function pointer is executed."]
#[must_use]
#[rust_name = #connect_ident_rust_str]
fn #connect_ident_cpp(self: #self_type_cxx, func: #unsafe_call fn(#self_type_cxx, #(#parameters),*), conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection;
fn #connect_ident_cpp(self: #self_type_cxx, func: #unsafe_call fn(#self_type_cxx, #(#parameters_cxx),*), conn_type: CxxQtConnectionType) -> CxxQtQMetaObjectConnection;
}
},
],
Expand All @@ -88,7 +96,7 @@ pub fn generate_rust_signals(
#[doc = "\n"]
#[doc = "Note that this method uses a AutoConnection connection type."]
#[must_use]
pub fn #on_ident_rust(self: #self_type, func: fn(#self_type, #(#parameters),*)) -> cxx_qt_lib::QMetaObjectConnection
pub fn #on_ident_rust(self: #self_type_qualified, func: fn(#self_type_qualified, #(#parameters_qualified),*)) -> cxx_qt_lib::QMetaObjectConnection
{
self.#connect_ident_rust(func, cxx_qt_lib::ConnectionType::AutoConnection)
}
Expand Down Expand Up @@ -247,7 +255,7 @@ mod tests {
#[doc = "\n"]
#[doc = "Note that this method uses a AutoConnection connection type."]
#[must_use]
pub fn on_data_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, trivial: i32, opaque: UniquePtr<QColor>)) -> cxx_qt_lib::QMetaObjectConnection
pub fn on_data_changed(self: core::pin::Pin<&mut MyObject>, func: fn(core::pin::Pin<&mut MyObject>, trivial: i32, opaque: cxx::UniquePtr<QColor>)) -> cxx_qt_lib::QMetaObjectConnection
{
self.connect_data_changed(func, cxx_qt_lib::ConnectionType::AutoConnection)
}
Expand Down
Loading

0 comments on commit e3013b1

Please sign in to comment.