From 92fe974f4975467c5a7b1d184e983251704d7ea2 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Thu, 15 Sep 2022 14:31:36 +0100 Subject: [PATCH] cxx-qt-gen: add support for multiple qobjects in rust writer --- crates/cxx-qt-gen/src/extract.rs | 15 +- crates/cxx-qt-gen/src/gen_rs.rs | 72 ++-- crates/cxx-qt-gen/src/generator/rust/mod.rs | 18 +- .../cxx-qt-gen/src/generator/rust/qobject.rs | 21 + crates/cxx-qt-gen/src/writer/rust/mod.rs | 381 ++++++++++++++---- .../cxx-qt-gen/test_outputs/custom_default.rs | 14 +- crates/cxx-qt-gen/test_outputs/invokables.rs | 30 +- crates/cxx-qt-gen/test_outputs/naming.rs | 22 +- crates/cxx-qt-gen/test_outputs/passthrough.rs | 44 +- crates/cxx-qt-gen/test_outputs/properties.rs | 28 +- crates/cxx-qt-gen/test_outputs/signals.rs | 28 +- .../test_outputs/types_primitive_property.rs | 14 +- .../test_outputs/types_qt_invokable.rs | 50 +-- .../test_outputs/types_qt_property.rs | 51 +-- 14 files changed, 525 insertions(+), 263 deletions(-) create mode 100644 crates/cxx-qt-gen/src/generator/rust/qobject.rs diff --git a/crates/cxx-qt-gen/src/extract.rs b/crates/cxx-qt-gen/src/extract.rs index 89c62dcb0..39e5c268b 100644 --- a/crates/cxx-qt-gen/src/extract.rs +++ b/crates/cxx-qt-gen/src/extract.rs @@ -9,7 +9,7 @@ use crate::parser::{ }; use proc_macro2::{Span, TokenStream}; use std::result::Result; -use syn::{spanned::Spanned, token::Brace, *}; +use syn::{spanned::Spanned, *}; /// Describes a Qt type #[derive(Debug, PartialEq)] @@ -129,8 +129,6 @@ pub struct QObject { pub(crate) signal_ident: Option, /// The namespace to use for C++ pub(crate) namespace: String, - /// Items we just pass through to the CXX bridge - pub(crate) cxx_items: Vec, /// The original Rust mod for the struct pub(crate) original_mod: ItemMod, /// The original Rust struct that the object was generated from @@ -583,14 +581,6 @@ pub fn extract_qobject(module: &ItemMod) -> Result { .chain(qobject.others.iter()) .cloned() .collect::>(); - // A list of items we will pass through to the CXX bridge - // - // TODO: for now this just includes ItemForeignMod but later this will switch to all non CXX-Qt items - let cxx_items = parser - .passthrough_module - .content - .unwrap_or((Brace::default(), vec![])) - .1; // Read properties let object_properties = qobject @@ -622,7 +612,6 @@ pub fn extract_qobject(module: &ItemMod) -> Result { signals: object_signals, signal_ident, namespace: parser.cxx_qt_data.namespace, - cxx_items, original_mod, original_signal_enum, original_rust_struct, @@ -791,7 +780,7 @@ mod tests { assert_eq!(qobject.original_passthrough_decls.len(), 3); // Check that we have a CXX passthrough item - assert_eq!(qobject.cxx_items.len(), 18); + assert_eq!(qobject.original_mod.content.unwrap().1.len(), 18); } #[test] diff --git a/crates/cxx-qt-gen/src/gen_rs.rs b/crates/cxx-qt-gen/src/gen_rs.rs index 55b8fd2bf..c26482792 100644 --- a/crates/cxx-qt-gen/src/gen_rs.rs +++ b/crates/cxx-qt-gen/src/gen_rs.rs @@ -5,13 +5,13 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, ToTokens}; -use syn::ItemMod; +use syn::{Item, ItemMod}; use crate::extract::{Invokable, Property, QObject, QtTypes}; use crate::generator::{ naming, naming::{property::QPropertyName, qobject::QObjectName}, - rust::GeneratedRustBlocks, + rust::{qobject::GeneratedRustQObjectBlocks, GeneratedRustBlocks}, }; use crate::writer::rust::write_rust; @@ -189,7 +189,7 @@ fn generate_invokable_cxx_declaration(obj: &QObject, i: &Invokable) -> TokenStre } /// Generate Rust code that used CXX to interact with the C++ code generated for a QObject -pub fn generate_qobject_cxx(obj: &QObject) -> Result { +pub fn generate_qobject_cxx(obj: &QObject) -> Result, TokenStream> { // Cache the original and rust class names, these are used multiple times later let qobject_idents = naming::qobject::QObjectName::from(&obj.original_rust_struct.ident); let cpp_class_name_cpp = qobject_idents.cpp_class.cpp.to_string(); @@ -284,40 +284,35 @@ pub fn generate_qobject_cxx(obj: &QObject) -> Result { // Build the import path for the C++ header let import_path = format!("cxx-qt-gen/include/{}.cxxqt.h", cxx_stem); - // Build the module ident - let mod_attrs = &obj.original_mod.attrs; - let mod_ident = &obj.original_mod.ident; - let mod_vis = &obj.original_mod.vis; - - // Retrieve the passthrough items to CXX - let cxx_items = &obj.cxx_items; - // Build the CXX bridge - let output = quote! { - #(#mod_attrs)* - #mod_vis mod #mod_ident { - unsafe extern "C++" { - include!(#import_path); + Ok(vec![ + syn::parse2::( + quote! { + unsafe extern "C++" { + include!(#import_path); - #[cxx_name = #cpp_class_name_cpp] - type #cpp_class_name_rust; + #[cxx_name = #cpp_class_name_cpp] + type #cpp_class_name_rust; - #(#cpp_functions)* + #(#cpp_functions)* + } } - - extern "Rust" { - #[cxx_name = #rust_struct_name_cpp] - type #rust_struct_name_rust; - - #(#rs_functions)* + .into_token_stream(), + ) + .map_err(|err| err.to_compile_error())?, + syn::parse2::( + quote! { + extern "Rust" { + #[cxx_name = #rust_struct_name_cpp] + type #rust_struct_name_rust; + + #(#rs_functions)* + } } - - #(#cxx_items)* - } - }; - - // Convert into an ItemMod for our writer phase - syn::parse2::(output.into_token_stream()).map_err(|err| err.to_compile_error()) + .into_token_stream(), + ) + .map_err(|err| err.to_compile_error())?, + ]) } fn generate_signal_methods_rs(obj: &QObject) -> Result, TokenStream> { @@ -534,7 +529,7 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result { let cxx_qt_thread_ident = qobject_idents.cxx_qt_thread_class; // Generate cxx block - let cxx_block = generate_qobject_cxx(obj)?; + let cxx_mod_contents = generate_qobject_cxx(obj)?; // Generate property methods from the object let signal_methods = generate_signal_methods_rs(obj)?; @@ -615,17 +610,22 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result { }) .map_err(|err| err.to_compile_error())?; - let generated = GeneratedRustBlocks { - cxx_mod: cxx_block, + let qobjects = vec![GeneratedRustQObjectBlocks { + cxx_mod_contents, cxx_qt_mod_contents: cxx_qt_mod_fake .content .unwrap_or((syn::token::Brace::default(), vec![])) .1, cpp_struct_ident: cpp_class_name_rust, cxx_qt_thread_ident, - namespace: obj.namespace.to_owned(), namespace_internals, rust_struct_ident: obj.ident.clone(), + }]; + + let generated = GeneratedRustBlocks { + cxx_mod: obj.original_mod.clone(), + namespace: obj.namespace.to_owned(), + qobjects, }; Ok(write_rust(&generated)) } diff --git a/crates/cxx-qt-gen/src/generator/rust/mod.rs b/crates/cxx-qt-gen/src/generator/rust/mod.rs index ad6198c37..85840e0d8 100644 --- a/crates/cxx-qt-gen/src/generator/rust/mod.rs +++ b/crates/cxx-qt-gen/src/generator/rust/mod.rs @@ -3,22 +3,16 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use syn::{Ident, Item, ItemMod}; +use syn::ItemMod; + +pub mod qobject; /// Representation of the generated Rust code for a QObject pub struct GeneratedRustBlocks { - /// Module for the CXX bridge + /// Module for the CXX bridge with passthrough items pub cxx_mod: ItemMod, - /// Items for the CXX-Qt module - pub cxx_qt_mod_contents: Vec, - /// Ident of the Rust name for the C++ object - pub cpp_struct_ident: Ident, - /// Ident of the CxxQtThread object - pub cxx_qt_thread_ident: Ident, /// Ident of the namespace of the QObject pub namespace: String, - /// Ident of the namespace for CXX-Qt internals of the QObject - pub namespace_internals: String, - /// Ident of the Rust name for the Rust object - pub rust_struct_ident: Ident, + /// Generated QObject blocks + pub qobjects: Vec, } diff --git a/crates/cxx-qt-gen/src/generator/rust/qobject.rs b/crates/cxx-qt-gen/src/generator/rust/qobject.rs new file mode 100644 index 000000000..5f3687ca0 --- /dev/null +++ b/crates/cxx-qt-gen/src/generator/rust/qobject.rs @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company +// SPDX-FileContributor: Andrew Hayzen +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use syn::{Ident, Item}; + +pub struct GeneratedRustQObjectBlocks { + /// Module for the CXX bridge + pub cxx_mod_contents: Vec, + /// Items for the CXX-Qt module + pub cxx_qt_mod_contents: Vec, + /// Ident of the Rust name for the C++ object + pub cpp_struct_ident: Ident, + /// Ident of the CxxQtThread object + pub cxx_qt_thread_ident: Ident, + /// Ident of the namespace for CXX-Qt internals of the QObject + pub namespace_internals: String, + /// Ident of the Rust name for the Rust object + pub rust_struct_ident: Ident, +} diff --git a/crates/cxx-qt-gen/src/writer/rust/mod.rs b/crates/cxx-qt-gen/src/writer/rust/mod.rs index d2b40f997..db5044807 100644 --- a/crates/cxx-qt-gen/src/writer/rust/mod.rs +++ b/crates/cxx-qt-gen/src/writer/rust/mod.rs @@ -3,11 +3,11 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::generator::rust::GeneratedRustBlocks; +use crate::generator::rust::{qobject::GeneratedRustQObjectBlocks, GeneratedRustBlocks}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; -use syn::Ident; +use syn::{Ident, Item}; /// Mangle an input name with an object name /// @@ -22,22 +22,18 @@ fn mangle(name: &str, object: &Ident) -> Ident { } /// Return common blocks for CXX bridge which the C++ writer adds as well -fn cxx_common_blocks( - cpp_struct_ident: &Ident, - rust_struct_ident: &Ident, - cxx_qt_thread_ident: &Ident, - namespace_internals: &String, -) -> Vec { +fn cxx_bridge_common_blocks(qobject: &GeneratedRustQObjectBlocks) -> Vec { + let cpp_struct_ident = &qobject.cpp_struct_ident; + let rust_struct_ident = &qobject.rust_struct_ident; + let cxx_qt_thread_ident = &qobject.cxx_qt_thread_ident; + let namespace_internals = &qobject.namespace_internals; + let new_cpp_obj_str = mangle("new_cpp_object", cpp_struct_ident).to_string(); let create_rs_ident = mangle("create_rs", rust_struct_ident); vec![ quote! { unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - // Specialised version of CxxQtThread // // CXX doesn't support having generic types in the function yet @@ -74,35 +70,67 @@ fn cxx_common_blocks( ] } +/// Return common blocks for CXX-Qt implementation which the C++ writer adds as well +fn cxx_qt_common_blocks(qobject: &GeneratedRustQObjectBlocks) -> Vec { + let rust_struct_ident = &qobject.rust_struct_ident; + let cxx_qt_thread_ident = &qobject.cxx_qt_thread_ident; + let create_rs_ident = mangle("create_rs", rust_struct_ident); + + vec![ + quote! { + unsafe impl Send for #cxx_qt_thread_ident {} + }, + quote! { + pub fn #create_rs_ident() -> std::boxed::Box<#rust_struct_ident> { + std::default::Default::default() + } + }, + ] +} + /// For a given GeneratedRustBlocks write this into a Rust TokenStream pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { - // Retrieve the struct idents - let cpp_struct_ident = &generated.cpp_struct_ident; - let rust_struct_ident = &generated.rust_struct_ident; - let cxx_qt_thread_ident = &generated.cxx_qt_thread_ident; - // Build the module idents let cxx_mod_ident = &generated.cxx_mod.ident; let cxx_qt_mod_ident = format_ident!("cxx_qt_{}", cxx_mod_ident); // Retrieve the module contents and namespace let mut cxx_mod = generated.cxx_mod.clone(); - let cxx_qt_mod_contents = &generated.cxx_qt_mod_contents; + let mut cxx_qt_mod_contents: Vec = vec![]; let namespace = &generated.namespace; - let namespace_internals = &generated.namespace_internals; - - // Inject the common blocks into the bridge which we need - let cxx_mod_items = &mut cxx_mod.content.as_mut().expect("").1; - for block in cxx_common_blocks( - cpp_struct_ident, - rust_struct_ident, - cxx_qt_thread_ident, - namespace_internals, - ) { - cxx_mod_items.push(syn::parse2(block).expect("Could not build CXX common block")); - } - let create_rs_ident = mangle("create_rs", rust_struct_ident); + // Add comment includes for all objects + cxx_mod.content.as_mut().expect("").1.push( + syn::parse2(quote! { + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + }) + .expect("Could not build CXX common block"), + ); + + for qobject in &generated.qobjects { + // Inject the common blocks into the bridge which we need + let cxx_mod_items = &mut cxx_mod.content.as_mut().expect("").1; + cxx_mod_items.extend_from_slice(&qobject.cxx_mod_contents); + cxx_mod_items.append( + &mut cxx_bridge_common_blocks(qobject) + .into_iter() + .map(|block| syn::parse2(block).expect("Could not build CXX common block")) + .collect(), + ); + + // Inject the common blocks into the implementation we need + cxx_qt_mod_contents.extend_from_slice(&qobject.cxx_qt_mod_contents); + cxx_qt_mod_contents.append( + &mut cxx_qt_common_blocks(qobject) + .into_iter() + .map(|block| syn::parse2(block).expect("Could not build CXX-Qt common block")) + .collect(), + ); + } quote! { #[cxx::bridge(namespace = #namespace)] @@ -114,13 +142,7 @@ pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for #cxx_qt_thread_ident {} - #(#cxx_qt_mod_contents)* - - pub fn #create_rs_ident() -> std::boxed::Box<#rust_struct_ident> { - std::default::Default::default() - } } } .into_token_stream() @@ -130,7 +152,7 @@ pub fn write_rust(generated: &GeneratedRustBlocks) -> TokenStream { mod tests { use super::*; - use crate::tests::tokens_to_syn; + use crate::{generator::rust::qobject::GeneratedRustQObjectBlocks, tests::tokens_to_syn}; use pretty_assertions::assert_str_eq; use quote::format_ident; @@ -138,36 +160,120 @@ mod tests { pub fn create_generated_rust() -> GeneratedRustBlocks { GeneratedRustBlocks { cxx_mod: tokens_to_syn(quote! { - mod ffi { - unsafe extern "C++" { - #[cxx_name = "MyObject"] - type MyObjectQt; - } - - extern "Rust" { - #[cxx_name = "MyObjectRust"] - type MyObject; - } - } + mod ffi {} }), - cxx_qt_mod_contents: vec![ - tokens_to_syn(quote! { - #[derive(Default)] - pub struct MyObject; - }), - tokens_to_syn(quote! { - impl MyObject { - fn rust_method(&self) { - + namespace: "cxx_qt::my_object".to_owned(), + qobjects: vec![GeneratedRustQObjectBlocks { + cxx_mod_contents: vec![ + tokens_to_syn(quote! { + unsafe extern "C++" { + #[cxx_name = "MyObject"] + type MyObjectQt; } - } - }), + }), + tokens_to_syn(quote! { + extern "Rust" { + #[cxx_name = "MyObjectRust"] + type MyObject; + } + }), + ], + cxx_qt_mod_contents: vec![ + tokens_to_syn(quote! { + #[derive(Default)] + pub struct MyObject; + }), + tokens_to_syn(quote! { + impl MyObject { + fn rust_method(&self) { + + } + } + }), + ], + cpp_struct_ident: format_ident!("MyObjectQt"), + cxx_qt_thread_ident: format_ident!("MyObjectCxxQtThread"), + namespace_internals: "cxx_qt::my_object::cxx_qt_my_object".to_owned(), + rust_struct_ident: format_ident!("MyObject"), + }], + } + } + + /// Helper to create a GeneratedRustBlocks for testing with multiple qobjects + pub fn create_generated_rust_multi_qobjects() -> GeneratedRustBlocks { + GeneratedRustBlocks { + cxx_mod: tokens_to_syn(quote! { + mod ffi {} + }), + namespace: "cxx_qt".to_owned(), + qobjects: vec![ + GeneratedRustQObjectBlocks { + cxx_mod_contents: vec![ + tokens_to_syn(quote! { + unsafe extern "C++" { + #[cxx_name = "FirstObject"] + type FirstObjectQt; + } + }), + tokens_to_syn(quote! { + extern "Rust" { + #[cxx_name = "FirstObjectRust"] + type FirstObject; + } + }), + ], + cxx_qt_mod_contents: vec![ + tokens_to_syn(quote! { + #[derive(Default)] + pub struct FirstObject; + }), + tokens_to_syn(quote! { + impl FirstObject { + fn rust_method(&self) { + + } + } + }), + ], + cpp_struct_ident: format_ident!("FirstObjectQt"), + cxx_qt_thread_ident: format_ident!("FirstObjectCxxQtThread"), + namespace_internals: "cxx_qt::cxx_qt_first_object".to_owned(), + rust_struct_ident: format_ident!("FirstObject"), + }, + GeneratedRustQObjectBlocks { + cxx_mod_contents: vec![ + tokens_to_syn(quote! { + unsafe extern "C++" { + #[cxx_name = "SecondObject"] + type SecondObjectQt; + } + }), + tokens_to_syn(quote! { + extern "Rust" { + #[cxx_name = "SecondObjectRust"] + type SecondObject; + } + }), + ], + cxx_qt_mod_contents: vec![ + tokens_to_syn(quote! { + #[derive(Default)] + pub struct SecondObject; + }), + tokens_to_syn(quote! { + impl SecondObject { + fn rust_method(&self) { + + } + } + }), + ], + cpp_struct_ident: format_ident!("SecondObjectQt"), + cxx_qt_thread_ident: format_ident!("SecondObjectCxxQtThread"), + namespace_internals: "cxx_qt::cxx_qt_second_object".to_owned(), + rust_struct_ident: format_ident!("SecondObject"), + }, ], - cpp_struct_ident: format_ident!("MyObjectQt"), - cxx_qt_thread_ident: format_ident!("MyObjectCxxQtThread"), - namespace: "cxx_qt::my_object".to_owned(), - namespace_internals: "cxx_qt::my_object::cxx_qt_my_object".to_owned(), - rust_struct_ident: format_ident!("MyObject"), } } @@ -176,6 +282,12 @@ mod tests { quote! { #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { #[cxx_name = "MyObject"] type MyObjectQt; @@ -187,10 +299,6 @@ mod tests { } unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -223,8 +331,6 @@ mod tests { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - #[derive(Default)] pub struct MyObject; @@ -234,6 +340,8 @@ mod tests { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } @@ -243,10 +351,141 @@ mod tests { .to_string() } + /// Helper for the expected Rust with multiple qobjects + pub fn expected_rust_multi_qobjects() -> String { + quote! { + #[cxx::bridge(namespace = "cxx_qt")] + mod ffi { + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + + unsafe extern "C++" { + #[cxx_name = "FirstObject"] + type FirstObjectQt; + } + + extern "Rust" { + #[cxx_name = "FirstObjectRust"] + type FirstObject; + } + + unsafe extern "C++" { + type FirstObjectCxxQtThread; + + #[cxx_name = "unsafeRust"] + fn rust(self: &FirstObjectQt) -> &FirstObject; + + #[cxx_name = "qtThread"] + fn qt_thread(self: &FirstObjectQt) -> UniquePtr; + fn queue(self: &FirstObjectCxxQtThread, func: fn(ctx: Pin<&mut FirstObjectQt>)) -> Result<()>; + + #[rust_name = "new_cpp_object_first_object_qt"] + #[namespace = "cxx_qt::cxx_qt_first_object"] + fn newCppObject() -> UniquePtr; + } + + extern "C++" { + #[cxx_name = "unsafeRustMut"] + unsafe fn rust_mut(self: Pin<&mut FirstObjectQt>) -> Pin<&mut FirstObject>; + } + + extern "Rust" { + #[cxx_name = "createRs"] + #[namespace = "cxx_qt::cxx_qt_first_object"] + fn create_rs_first_object() -> Box; + } + unsafe extern "C++" { + #[cxx_name = "SecondObject"] + type SecondObjectQt; + } + + extern "Rust" { + #[cxx_name = "SecondObjectRust"] + type SecondObject; + } + + unsafe extern "C++" { + type SecondObjectCxxQtThread; + + #[cxx_name = "unsafeRust"] + fn rust(self: &SecondObjectQt) -> &SecondObject; + + #[cxx_name = "qtThread"] + fn qt_thread(self: &SecondObjectQt) -> UniquePtr; + fn queue(self: &SecondObjectCxxQtThread, func: fn(ctx: Pin<&mut SecondObjectQt>)) -> Result<()>; + + #[rust_name = "new_cpp_object_second_object_qt"] + #[namespace = "cxx_qt::cxx_qt_second_object"] + fn newCppObject() -> UniquePtr; + } + + extern "C++" { + #[cxx_name = "unsafeRustMut"] + unsafe fn rust_mut(self: Pin<&mut SecondObjectQt>) -> Pin<&mut SecondObject>; + } + + extern "Rust" { + #[cxx_name = "createRs"] + #[namespace = "cxx_qt::cxx_qt_second_object"] + fn create_rs_second_object() -> Box; + } + } + + pub use self::cxx_qt_ffi::*; + mod cxx_qt_ffi { + use super::ffi::*; + + type UniquePtr = cxx::UniquePtr; + + #[derive(Default)] + pub struct FirstObject; + + impl FirstObject { + fn rust_method(&self) { + + } + } + + unsafe impl Send for FirstObjectCxxQtThread {} + + pub fn create_rs_first_object() -> std::boxed::Box { + std::default::Default::default() + } + + #[derive(Default)] + pub struct SecondObject; + + impl SecondObject { + fn rust_method(&self) { + + } + } + + unsafe impl Send for SecondObjectCxxQtThread {} + + pub fn create_rs_second_object() -> std::boxed::Box { + std::default::Default::default() + } + } + } + .into_token_stream() + .to_string() + } + #[test] fn test_write_rust() { let generated = create_generated_rust(); let result = write_rust(&generated); assert_str_eq!(result.to_string(), expected_rust()); } + + #[test] + fn test_write_rust_multi_qobjects() { + let generated = create_generated_rust_multi_qobjects(); + let result = write_rust(&generated); + assert_str_eq!(result.to_string(), expected_rust_multi_qobjects()); + } } diff --git a/crates/cxx-qt-gen/test_outputs/custom_default.rs b/crates/cxx-qt-gen/test_outputs/custom_default.rs index 5113fab45..af5791afd 100644 --- a/crates/cxx-qt-gen/test_outputs/custom_default.rs +++ b/crates/cxx-qt-gen/test_outputs/custom_default.rs @@ -1,5 +1,11 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -21,10 +27,6 @@ mod ffi { } unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -57,8 +59,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; pub struct MyObject { @@ -98,6 +98,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + 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 53c984e30..bb03a531e 100644 --- a/crates/cxx-qt-gen/test_outputs/invokables.rs +++ b/crates/cxx-qt-gen/test_outputs/invokables.rs @@ -1,5 +1,19 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + #[namespace = ""] + unsafe extern "C++" { + include!("cxx-qt-lib/include/qt_types.h"); + type QColor = cxx_qt_lib::QColor; + type QPoint = cxx_qt_lib::QPoint; + type QString = cxx_qt_lib::QString; + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -40,19 +54,7 @@ mod ffi { ) -> UniquePtr; } - #[namespace = ""] - unsafe extern "C++" { - include!("cxx-qt-lib/include/qt_types.h"); - type QColor = cxx_qt_lib::QColor; - type QPoint = cxx_qt_lib::QPoint; - type QString = cxx_qt_lib::QString; - } - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -85,8 +87,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -182,6 +182,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } diff --git a/crates/cxx-qt-gen/test_outputs/naming.rs b/crates/cxx-qt-gen/test_outputs/naming.rs index 6ffb2ca5c..1b3f2f160 100644 --- a/crates/cxx-qt-gen/test_outputs/naming.rs +++ b/crates/cxx-qt-gen/test_outputs/naming.rs @@ -1,5 +1,15 @@ #[cxx::bridge(namespace = "")] mod ffi { + unsafe extern "C++" { + include ! (< QtCore / QStringListModel >); + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -24,14 +34,6 @@ mod ffi { } unsafe extern "C++" { - include ! (< QtCore / QStringListModel >); - } - - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -64,8 +66,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -105,6 +105,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } diff --git a/crates/cxx-qt-gen/test_outputs/passthrough.rs b/crates/cxx-qt-gen/test_outputs/passthrough.rs index aa600706e..a260a6538 100644 --- a/crates/cxx-qt-gen/test_outputs/passthrough.rs +++ b/crates/cxx-qt-gen/test_outputs/passthrough.rs @@ -2,25 +2,6 @@ #[attrA] #[attrB] pub mod ffi { - unsafe extern "C++" { - include!("cxx-qt-gen/include/my_object.cxxqt.h"); - - #[cxx_name = "MyObject"] - type MyObjectQt; - - #[rust_name = "emit_number_changed"] - fn emitNumberChanged(self: Pin<&mut MyObjectQt>); - } - - extern "Rust" { - #[cxx_name = "MyObjectRust"] - type MyObject; - #[cxx_name = "getNumber"] - unsafe fn get_number<'a>(self: &'a MyObject, cpp: &'a MyObjectQt) -> &'a i32; - #[cxx_name = "setNumber"] - fn set_number(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>, value: i32); - } - const MAX: u16 = 65535; enum Event { @@ -82,7 +63,28 @@ pub mod ffi { include ! (< QtCore / QObject >); include!("cxx-qt-lib/include/convert.h"); include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + + unsafe extern "C++" { + include!("cxx-qt-gen/include/my_object.cxxqt.h"); + + #[cxx_name = "MyObject"] + type MyObjectQt; + + #[rust_name = "emit_number_changed"] + fn emitNumberChanged(self: Pin<&mut MyObjectQt>); + } + + extern "Rust" { + #[cxx_name = "MyObjectRust"] + type MyObject; + #[cxx_name = "getNumber"] + unsafe fn get_number<'a>(self: &'a MyObject, cpp: &'a MyObjectQt) -> &'a i32; + #[cxx_name = "setNumber"] + fn set_number(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>, value: i32); + } + unsafe extern "C++" { type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -115,8 +117,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -165,6 +165,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_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 6a04060b8..9ab89ce4a 100644 --- a/crates/cxx-qt-gen/test_outputs/properties.rs +++ b/crates/cxx-qt-gen/test_outputs/properties.rs @@ -1,5 +1,18 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + #[namespace = ""] + unsafe extern "C++" { + include!("cxx-qt-lib/include/qt_types.h"); + type QColor = cxx_qt_lib::QColor; + type QPoint = cxx_qt_lib::QPoint; + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -34,18 +47,7 @@ mod ffi { fn set_opaque(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>, value: UniquePtr); } - #[namespace = ""] - unsafe extern "C++" { - include!("cxx-qt-lib/include/qt_types.h"); - type QColor = cxx_qt_lib::QColor; - type QPoint = cxx_qt_lib::QPoint; - } - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -78,8 +80,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -150,6 +150,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + 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 5dccfa912..92143bac0 100644 --- a/crates/cxx-qt-gen/test_outputs/signals.rs +++ b/crates/cxx-qt-gen/test_outputs/signals.rs @@ -1,5 +1,18 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + #[namespace = ""] + unsafe extern "C++" { + include!("cxx-qt-lib/include/qt_types.h"); + type QPoint = cxx_qt_lib::QPoint; + type QVariant = cxx_qt_lib::QVariant; + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -26,18 +39,7 @@ mod ffi { fn invokable_wrapper(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>); } - #[namespace = ""] - unsafe extern "C++" { - include!("cxx-qt-lib/include/qt_types.h"); - type QPoint = cxx_qt_lib::QPoint; - type QVariant = cxx_qt_lib::QVariant; - } - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -70,8 +72,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; enum MySignals { @@ -113,6 +113,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } diff --git a/crates/cxx-qt-gen/test_outputs/types_primitive_property.rs b/crates/cxx-qt-gen/test_outputs/types_primitive_property.rs index 6815433fa..0d1ca834e 100644 --- a/crates/cxx-qt-gen/test_outputs/types_primitive_property.rs +++ b/crates/cxx-qt-gen/test_outputs/types_primitive_property.rs @@ -1,5 +1,11 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -85,10 +91,6 @@ mod ffi { } unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -121,8 +123,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -313,6 +313,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } diff --git a/crates/cxx-qt-gen/test_outputs/types_qt_invokable.rs b/crates/cxx-qt-gen/test_outputs/types_qt_invokable.rs index 55b1aee7b..a4d63461e 100644 --- a/crates/cxx-qt-gen/test_outputs/types_qt_invokable.rs +++ b/crates/cxx-qt-gen/test_outputs/types_qt_invokable.rs @@ -1,5 +1,29 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + #[namespace = ""] + unsafe extern "C++" { + include!("cxx-qt-lib/include/qt_types.h"); + type QColor = cxx_qt_lib::QColor; + type QDate = cxx_qt_lib::QDate; + type QDateTime = cxx_qt_lib::QDateTime; + type QPoint = cxx_qt_lib::QPoint; + type QPointF = cxx_qt_lib::QPointF; + type QRect = cxx_qt_lib::QRect; + type QRectF = cxx_qt_lib::QRectF; + type QSize = cxx_qt_lib::QSize; + type QSizeF = cxx_qt_lib::QSizeF; + type QString = cxx_qt_lib::QString; + type QTime = cxx_qt_lib::QTime; + type QUrl = cxx_qt_lib::QUrl; + type QVariant = cxx_qt_lib::QVariant; + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -67,29 +91,7 @@ mod ffi { ) -> UniquePtr; } - #[namespace = ""] - unsafe extern "C++" { - include!("cxx-qt-lib/include/qt_types.h"); - type QColor = cxx_qt_lib::QColor; - type QDate = cxx_qt_lib::QDate; - type QDateTime = cxx_qt_lib::QDateTime; - type QPoint = cxx_qt_lib::QPoint; - type QPointF = cxx_qt_lib::QPointF; - type QRect = cxx_qt_lib::QRect; - type QRectF = cxx_qt_lib::QRectF; - type QSize = cxx_qt_lib::QSize; - type QSizeF = cxx_qt_lib::QSizeF; - type QString = cxx_qt_lib::QString; - type QTime = cxx_qt_lib::QTime; - type QUrl = cxx_qt_lib::QUrl; - type QVariant = cxx_qt_lib::QVariant; - } - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -122,8 +124,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -289,6 +289,8 @@ mod cxx_qt_ffi { } } + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() } diff --git a/crates/cxx-qt-gen/test_outputs/types_qt_property.rs b/crates/cxx-qt-gen/test_outputs/types_qt_property.rs index 77f5dd1e6..f452f97a1 100644 --- a/crates/cxx-qt-gen/test_outputs/types_qt_property.rs +++ b/crates/cxx-qt-gen/test_outputs/types_qt_property.rs @@ -1,5 +1,29 @@ #[cxx::bridge(namespace = "cxx_qt::my_object")] mod ffi { + #[namespace = ""] + unsafe extern "C++" { + include!("cxx-qt-lib/include/qt_types.h"); + type QColor = cxx_qt_lib::QColor; + type QDate = cxx_qt_lib::QDate; + type QDateTime = cxx_qt_lib::QDateTime; + type QPoint = cxx_qt_lib::QPoint; + type QPointF = cxx_qt_lib::QPointF; + type QRect = cxx_qt_lib::QRect; + type QRectF = cxx_qt_lib::QRectF; + type QSize = cxx_qt_lib::QSize; + type QSizeF = cxx_qt_lib::QSizeF; + type QString = cxx_qt_lib::QString; + type QTime = cxx_qt_lib::QTime; + type QUrl = cxx_qt_lib::QUrl; + type QVariant = cxx_qt_lib::QVariant; + } + + unsafe extern "C++" { + include ! (< QtCore / QObject >); + include!("cxx-qt-lib/include/convert.h"); + include!("cxx-qt-lib/include/cxxqt_thread.h"); + } + unsafe extern "C++" { include!("cxx-qt-gen/include/my_object.cxxqt.h"); @@ -127,29 +151,7 @@ mod ffi { fn set_variant(self: &mut MyObject, cpp: Pin<&mut MyObjectQt>, value: UniquePtr); } - #[namespace = ""] unsafe extern "C++" { - include!("cxx-qt-lib/include/qt_types.h"); - type QColor = cxx_qt_lib::QColor; - type QDate = cxx_qt_lib::QDate; - type QDateTime = cxx_qt_lib::QDateTime; - type QPoint = cxx_qt_lib::QPoint; - type QPointF = cxx_qt_lib::QPointF; - type QRect = cxx_qt_lib::QRect; - type QRectF = cxx_qt_lib::QRectF; - type QSize = cxx_qt_lib::QSize; - type QSizeF = cxx_qt_lib::QSizeF; - type QString = cxx_qt_lib::QString; - type QTime = cxx_qt_lib::QTime; - type QUrl = cxx_qt_lib::QUrl; - type QVariant = cxx_qt_lib::QVariant; - } - - unsafe extern "C++" { - include ! (< QtCore / QObject >); - include!("cxx-qt-lib/include/convert.h"); - include!("cxx-qt-lib/include/cxxqt_thread.h"); - type MyObjectCxxQtThread; #[cxx_name = "unsafeRust"] @@ -182,8 +184,6 @@ mod cxx_qt_ffi { type UniquePtr = cxx::UniquePtr; - unsafe impl Send for MyObjectCxxQtThread {} - use std::pin::Pin; #[derive(Default)] @@ -453,6 +453,9 @@ mod cxx_qt_ffi { self.as_mut().emit_variant_changed(); } } + + unsafe impl Send for MyObjectCxxQtThread {} + pub fn create_rs_my_object() -> std::boxed::Box { std::default::Default::default() }