Skip to content

Commit

Permalink
cxx-qt-gen: use qualified mappings in impl T as well
Browse files Browse the repository at this point in the history
Related to #404
  • Loading branch information
ahayzen-kdab authored and Be-ing committed Jul 26, 2023
1 parent 4a185af commit 048a2ba
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 64 deletions.
22 changes: 16 additions & 6 deletions crates/cxx-qt-gen/src/generator/rust/cxxqttype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,27 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::generator::{naming::qobject::QObjectName, rust::qobject::GeneratedRustQObjectBlocks};
use std::collections::BTreeMap;

use crate::generator::{
naming::qobject::QObjectName, rust::qobject::GeneratedRustQObjectBlocks,
utils::rust::syn_ident_cxx_bridge_to_qualified_impl,
};
use quote::quote;
use syn::Result;
use syn::{Ident, Path, Result};

use super::fragment::RustFragmentPair;

pub fn generate(qobject_ident: &QObjectName) -> Result<GeneratedRustQObjectBlocks> {
pub fn generate(
qobject_ident: &QObjectName,
qualified_mappings: &BTreeMap<Ident, Path>,
) -> Result<GeneratedRustQObjectBlocks> {
let mut blocks = GeneratedRustQObjectBlocks::default();

let cpp_struct_ident = &qobject_ident.cpp_class.rust;
let rust_struct_ident = &qobject_ident.rust_struct.rust;
let qualified_impl =
syn_ident_cxx_bridge_to_qualified_impl(cpp_struct_ident, qualified_mappings);

let fragment = RustFragmentPair {
cxx_bridge: vec![
Expand All @@ -34,7 +44,7 @@ pub fn generate(qobject_ident: &QObjectName) -> Result<GeneratedRustQObjectBlock
],
implementation: vec![
quote! {
impl core::ops::Deref for #cpp_struct_ident {
impl core::ops::Deref for #qualified_impl {
type Target = #rust_struct_ident;

fn deref(&self) -> &Self::Target {
Expand All @@ -43,7 +53,7 @@ pub fn generate(qobject_ident: &QObjectName) -> Result<GeneratedRustQObjectBlock
}
},
quote! {
impl cxx_qt::CxxQtType for #cpp_struct_ident {
impl cxx_qt::CxxQtType for #qualified_impl {
type Rust = #rust_struct_ident;

fn rust(&self) -> &Self::Rust {
Expand Down Expand Up @@ -81,7 +91,7 @@ mod tests {
let qobject = create_parsed_qobject();
let qobject_idents = QObjectName::from(&qobject);

let generated = generate(&qobject_idents).unwrap();
let generated = generate(&qobject_idents, &BTreeMap::<Ident, Path>::default()).unwrap();

assert_eq!(generated.cxx_mod_contents.len(), 2);
assert_eq!(generated.cxx_qt_mod_contents.len(), 2);
Expand Down
6 changes: 4 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/property/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::generator::{
naming::{property::QPropertyName, qobject::QObjectName},
rust::fragment::RustFragmentPair,
utils::rust::syn_type_cxx_bridge_to_qualified,
utils::rust::{syn_ident_cxx_bridge_to_qualified_impl, syn_type_cxx_bridge_to_qualified},
};
use quote::quote;
use std::collections::BTreeMap;
Expand All @@ -24,6 +24,8 @@ pub fn generate(
let ident = &idents.name.rust;
let ident_str = ident.to_string();
let qualified_ty = syn_type_cxx_bridge_to_qualified(cxx_ty, qualified_mappings);
let qualified_impl =
syn_ident_cxx_bridge_to_qualified_impl(cpp_class_name_rust, qualified_mappings);

RustFragmentPair {
cxx_bridge: vec![quote! {
Expand All @@ -33,7 +35,7 @@ pub fn generate(
}
}],
implementation: vec![quote! {
impl #cpp_class_name_rust {
impl #qualified_impl {
#[doc = "Getter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #getter_rust(&self) -> &#qualified_ty {
Expand Down
9 changes: 7 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/property/setter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use crate::generator::{
naming::{property::QPropertyName, qobject::QObjectName},
rust::fragment::RustFragmentPair,
utils::rust::{syn_type_cxx_bridge_to_qualified, syn_type_is_cxx_bridge_unsafe},
utils::rust::{
syn_ident_cxx_bridge_to_qualified_impl, syn_type_cxx_bridge_to_qualified,
syn_type_is_cxx_bridge_unsafe,
},
};
use quote::quote;
use std::collections::BTreeMap;
Expand All @@ -25,6 +28,8 @@ pub fn generate(
let ident_str = ident.to_string();
let notify_ident = &idents.notify.rust;
let qualified_ty = syn_type_cxx_bridge_to_qualified(cxx_ty, qualified_mappings);
let qualified_impl =
syn_ident_cxx_bridge_to_qualified_impl(cpp_class_name_rust, qualified_mappings);

// Determine if unsafe is required due to an unsafe type
let has_unsafe = if syn_type_is_cxx_bridge_unsafe(cxx_ty) {
Expand All @@ -41,7 +46,7 @@ pub fn generate(
}
}],
implementation: vec![quote! {
impl #cpp_class_name_rust {
impl #qualified_impl {
#[doc = "Setter for the Q_PROPERTY "]
#[doc = #ident_str]
pub fn #setter_rust(mut self: core::pin::Pin<&mut Self>, value: #qualified_ty) {
Expand Down
16 changes: 11 additions & 5 deletions crates/cxx-qt-gen/src/generator/rust/qobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
invokable::generate_rust_invokables, property::generate_rust_properties,
signals::generate_rust_signals, threading,
},
utils::rust::syn_ident_cxx_bridge_to_qualified_impl,
},
parser::qobject::ParsedQObject,
};
Expand Down Expand Up @@ -125,6 +126,7 @@ impl GeneratedRustQObject {
generated.blocks.append(&mut threading::generate(
&qobject_idents,
&namespace_idents,
qualified_mappings,
)?);
}

Expand All @@ -133,12 +135,15 @@ impl GeneratedRustQObject {
// This could be implemented using an auto trait in the future once stable
// https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html
if qobject.locking {
let cpp_class_name_rust = &qobject_idents.cpp_class.rust;
let qualified_impl = syn_ident_cxx_bridge_to_qualified_impl(
&qobject_idents.cpp_class.rust,
qualified_mappings,
);
generated
.blocks
.cxx_qt_mod_contents
.push(syn::parse_quote! {
impl cxx_qt::Locking for #cpp_class_name_rust {}
impl cxx_qt::Locking for #qualified_impl {}
});
}

Expand All @@ -148,9 +153,10 @@ impl GeneratedRustQObject {
&namespace_idents,
)?);

generated
.blocks
.append(&mut cxxqttype::generate(&qobject_idents)?);
generated.blocks.append(&mut cxxqttype::generate(
&qobject_idents,
qualified_mappings,
)?);

Ok(generated)
}
Expand Down
6 changes: 4 additions & 2 deletions crates/cxx-qt-gen/src/generator/rust/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
generator::{
naming::{qobject::QObjectName, signals::QSignalName},
rust::{fragment::RustFragmentPair, qobject::GeneratedRustQObjectBlocks},
utils::rust::syn_type_cxx_bridge_to_qualified,
utils::rust::{syn_ident_cxx_bridge_to_qualified_impl, syn_type_cxx_bridge_to_qualified},
},
parser::signals::ParsedSignal,
};
Expand Down Expand Up @@ -64,6 +64,8 @@ pub fn generate_rust_signals(
};
let self_type_qualified =
syn_type_cxx_bridge_to_qualified(&self_type_cxx, qualified_mappings);
let qualified_impl =
syn_ident_cxx_bridge_to_qualified_impl(qobject_name, qualified_mappings);

let mut unsafe_block = None;
let mut unsafe_call = Some(quote! { unsafe });
Expand Down Expand Up @@ -94,7 +96,7 @@ pub fn generate_rust_signals(
},
],
implementation: vec![quote! {
impl #qobject_name {
impl #qualified_impl {
#[doc = "Connect the given function pointer to the signal "]
#[doc = #signal_name_cpp_str]
#[doc = ", so that when the signal is emitted the function pointer is executed."]
Expand Down
23 changes: 17 additions & 6 deletions crates/cxx-qt-gen/src/generator/rust/threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

use std::collections::BTreeMap;

use crate::generator::{
naming::{
namespace::{namespace_combine_ident, NamespaceName},
qobject::QObjectName,
},
rust::qobject::GeneratedRustQObjectBlocks,
utils::rust::syn_ident_cxx_bridge_to_qualified_impl,
};
use quote::quote;
use syn::Result;
use syn::{Ident, Path, Result};

use super::fragment::RustFragmentPair;

pub fn generate(
qobject_ident: &QObjectName,
namespace_ident: &NamespaceName,
qualified_mappings: &BTreeMap<Ident, Path>,
) -> Result<GeneratedRustQObjectBlocks> {
let mut blocks = GeneratedRustQObjectBlocks::default();

Expand All @@ -30,6 +34,8 @@ pub fn generate(
let namespace_internals = &namespace_ident.internal;
let cxx_qt_thread_ident_type_id_str =
namespace_combine_ident(&namespace_ident.namespace, cxx_qt_thread_ident);
let qualified_impl =
syn_ident_cxx_bridge_to_qualified_impl(cpp_struct_ident, qualified_mappings);

let fragment = RustFragmentPair {
cxx_bridge: vec![
Expand Down Expand Up @@ -81,7 +87,7 @@ pub fn generate(
],
implementation: vec![
quote! {
impl cxx_qt::Threading for #cpp_struct_ident {
impl cxx_qt::Threading for #qualified_impl {
type BoxedQueuedFn = #cxx_qt_thread_queued_fn_ident;
type ThreadingTypeId = cxx::type_id!(#cxx_qt_thread_ident_type_id_str);

Expand All @@ -93,7 +99,7 @@ pub fn generate(
#[doc(hidden)]
fn queue<F>(cxx_qt_thread: &#cxx_qt_thread_ident, f: F) -> std::result::Result<(), cxx::Exception>
where
F: FnOnce(core::pin::Pin<&mut #cpp_struct_ident>),
F: FnOnce(core::pin::Pin<&mut #qualified_impl>),
F: Send + 'static,
{
// Wrap the given closure and pass in to C++ function as an opaque type
Expand All @@ -102,7 +108,7 @@ pub fn generate(
#[allow(clippy::boxed_local)]
#[doc(hidden)]
fn func(
obj: core::pin::Pin<&mut #cpp_struct_ident>,
obj: core::pin::Pin<&mut #qualified_impl>,
arg: std::boxed::Box<#cxx_qt_thread_queued_fn_ident>,
) {
(arg.inner)(obj)
Expand All @@ -129,7 +135,7 @@ pub fn generate(
pub struct #cxx_qt_thread_queued_fn_ident {
// An opaque Rust type is required to be Sized.
// https://github.com/dtolnay/cxx/issues/665
inner: std::boxed::Box<dyn FnOnce(core::pin::Pin<&mut #cpp_struct_ident>) + Send>,
inner: std::boxed::Box<dyn FnOnce(core::pin::Pin<&mut #qualified_impl>) + Send>,
}
},
],
Expand Down Expand Up @@ -159,7 +165,12 @@ mod tests {
let qobject_idents = QObjectName::from(&qobject);
let namespace_ident = NamespaceName::from(&qobject);

let generated = generate(&qobject_idents, &namespace_ident).unwrap();
let generated = generate(
&qobject_idents,
&namespace_ident,
&BTreeMap::<Ident, Path>::default(),
)
.unwrap();

assert_eq!(generated.cxx_mod_contents.len(), 2);
assert_eq!(generated.cxx_qt_mod_contents.len(), 2);
Expand Down
31 changes: 28 additions & 3 deletions crates/cxx-qt-gen/src/generator/utils/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ use syn::{
GenericArgument, Ident, Path, PathArguments, PathSegment, ReturnType, Type, TypeReference,
};

/// Return a qualified version of the ident that can by used for impl T outside of a CXX bridge
///
/// Eg MyObject -> ffi::MyObject
///
/// Note that this does not handle CXX types such as UniquePtr -> cxx::UniquePtr.
/// This is just for resolving impl T {} -> impl module::T {}
pub(crate) fn syn_ident_cxx_bridge_to_qualified_impl(
ident: &syn::Ident,
qualified_mappings: &BTreeMap<Ident, Path>,
) -> syn::Path {
if let Some(qualified_path) = qualified_mappings.get(ident) {
qualified_path.clone()
} else {
Path::from(ident.clone())
}
}

/// Return a qualified version of the type that can by used outside of a CXX bridge
///
/// Eg Pin -> core::pin::Pin or UniquePtr -> cxx::UniquePtr
Expand Down Expand Up @@ -78,9 +95,7 @@ pub(crate) fn syn_type_cxx_bridge_to_qualified(

// If the path matches a known ident then used the qualified mapping
if let Some(ident) = ty_path.path.get_ident() {
if let Some(qualified_path) = qualified_mappings.get(ident) {
ty_path.path = qualified_path.clone();
}
ty_path.path = syn_ident_cxx_bridge_to_qualified_impl(ident, qualified_mappings);
}

return Type::Path(ty_path);
Expand Down Expand Up @@ -271,6 +286,16 @@ mod tests {
);
}

#[test]
fn test_syn_ident_cxx_bridge_to_qualified_impl_mapped() {
let mut mappings = BTreeMap::<Ident, Path>::default();
mappings.insert(format_ident!("A"), parse_quote! { ffi::B });
assert_eq!(
syn_ident_cxx_bridge_to_qualified_impl(&parse_quote! { A }, &mappings),
parse_quote! { ffi::B }
);
}

#[test]
fn test_syn_type_is_cxx_bridge_unsafe_path() {
assert!(!syn_type_is_cxx_bridge_unsafe(&parse_quote! { i32 }));
Expand Down
6 changes: 3 additions & 3 deletions crates/cxx-qt-gen/test_outputs/inheritance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,18 @@ pub mod cxx_qt_inheritance {
#[doc(hidden)]
type UniquePtr<T> = cxx::UniquePtr<T>;
type MyObjectRust = super::MyObjectRust;
impl cxx_qt::Locking for MyObject {}
impl cxx_qt::Locking for inheritance::MyObject {}
#[doc(hidden)]
pub fn create_rs_my_object_rust() -> std::boxed::Box<MyObjectRust> {
std::boxed::Box::new(core::default::Default::default())
}
impl core::ops::Deref for MyObject {
impl core::ops::Deref for inheritance::MyObject {
type Target = MyObjectRust;
fn deref(&self) -> &Self::Target {
self.cxx_qt_ffi_rust()
}
}
impl cxx_qt::CxxQtType for MyObject {
impl cxx_qt::CxxQtType for inheritance::MyObject {
type Rust = MyObjectRust;
fn rust(&self) -> &Self::Rust {
self.cxx_qt_ffi_rust()
Expand Down
Loading

0 comments on commit 048a2ba

Please sign in to comment.