Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cxx-qt-gen: add support for multiple qobjects in rust writer #250

Merged
merged 1 commit into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions crates/cxx-qt-gen/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -129,8 +129,6 @@ pub struct QObject {
pub(crate) signal_ident: Option<Ident>,
/// The namespace to use for C++
pub(crate) namespace: String,
/// Items we just pass through to the CXX bridge
pub(crate) cxx_items: Vec<Item>,
/// The original Rust mod for the struct
pub(crate) original_mod: ItemMod,
/// The original Rust struct that the object was generated from
Expand Down Expand Up @@ -583,14 +581,6 @@ pub fn extract_qobject(module: &ItemMod) -> Result<QObject, TokenStream> {
.chain(qobject.others.iter())
.cloned()
.collect::<Vec<Item>>();
// 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
Expand Down Expand Up @@ -622,7 +612,6 @@ pub fn extract_qobject(module: &ItemMod) -> Result<QObject, TokenStream> {
signals: object_signals,
signal_ident,
namespace: parser.cxx_qt_data.namespace,
cxx_items,
original_mod,
original_signal_enum,
original_rust_struct,
Expand Down Expand Up @@ -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]
Expand Down
72 changes: 36 additions & 36 deletions crates/cxx-qt-gen/src/gen_rs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<ItemMod, TokenStream> {
pub fn generate_qobject_cxx(obj: &QObject) -> Result<Vec<Item>, 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();
Expand Down Expand Up @@ -284,40 +284,35 @@ pub fn generate_qobject_cxx(obj: &QObject) -> Result<ItemMod, TokenStream> {
// 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::<Item>(
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::<Item>(
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::<ItemMod>(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<Vec<TokenStream>, TokenStream> {
Expand Down Expand Up @@ -534,7 +529,7 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result<TokenStream, TokenStream> {
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)?;
Expand Down Expand Up @@ -615,17 +610,22 @@ pub fn generate_qobject_rs(obj: &QObject) -> Result<TokenStream, TokenStream> {
})
.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))
}
Expand Down
18 changes: 6 additions & 12 deletions crates/cxx-qt-gen/src/generator/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item>,
/// 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<qobject::GeneratedRustQObjectBlocks>,
}
21 changes: 21 additions & 0 deletions crates/cxx-qt-gen/src/generator/rust/qobject.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
//
// 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<Item>,
/// Items for the CXX-Qt module
pub cxx_qt_mod_contents: Vec<Item>,
/// 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,
}
Loading