Skip to content

Commit

Permalink
cxx-qt-gen: use the module name or attribute for the CXX file names
Browse files Browse the repository at this point in the history
So that we can support multiple QObjects later in one module block,
use the module name or cxx_stem attribute as the output file name.

Later if the Rust API is ever stable we could use the inspection
APIs on Span to read the filename of the macro. This would mean
we would be the same as CXX but this requires nightly.
  • Loading branch information
ahayzen-kdab committed Oct 6, 2022
1 parent 5949819 commit d5f4f45
Show file tree
Hide file tree
Showing 37 changed files with 112 additions and 121 deletions.
16 changes: 1 addition & 15 deletions crates/cxx-qt-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,7 @@ impl GeneratedCpp {

let generated_rust = GeneratedRustBlocks::from(&parser).unwrap();
let rust_tokens = write_rust(&generated_rust);
// Use the qobject ident as the output file name?
//
// TODO: for now we use the qobject name but in the future this will come from elswhere
if parser.cxx_qt_data.qobjects.len() != 1 {
panic!("Expected one QObject in the ItemMod.");
}
file_ident = parser
.cxx_qt_data
.qobjects
.keys()
.take(1)
.next()
.unwrap()
.to_string()
.to_case(Case::Snake);
file_ident = parser.cxx_file_stem.clone();

// We need to do this and can't rely on the macro, as we need to generate the
// CXX bridge Rust code that is then fed into the cxx_gen generation.
Expand Down
36 changes: 21 additions & 15 deletions crates/cxx-qt-gen/src/generator/cpp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ pub mod qobject;
pub mod signal;
pub mod types;

use crate::generator::naming;
use crate::parser::Parser;
use qobject::GeneratedCppQObject;
use syn::{spanned::Spanned, Error, Result};
use syn::Result;

pub const RUST_OBJ_MUTEX_LOCK_GUARD: &str =
"const std::lock_guard<std::recursive_mutex> guard(*m_rustObjMutex);";
Expand All @@ -22,7 +21,7 @@ pub const CXX_QT_CONVERT: &str = "rust::cxxqtlib1::cxx_qt_convert";
/// Representation of the generated C++ code for a group of QObjects
pub struct GeneratedCppBlocks {
/// Stem of the CXX header to include
pub cxx_stem: String,
pub cxx_file_stem: String,
/// Ident of the common namespace of the QObjects
pub namespace: String,
/// Generated QObjects
Expand All @@ -31,18 +30,8 @@ pub struct GeneratedCppBlocks {

impl GeneratedCppBlocks {
pub fn from(parser: &Parser) -> Result<GeneratedCppBlocks> {
// TODO: for now we use the name of the first and only QObject
// later this needs to come from elsewhere
if parser.cxx_qt_data.qobjects.len() != 1 {
return Err(Error::new(
parser.passthrough_module.span(),
"Expected one QObject in the ItemMod.",
));
}
let qt_ident = parser.cxx_qt_data.qobjects.keys().take(1).next().unwrap();

Ok(GeneratedCppBlocks {
cxx_stem: naming::module::cxx_stem_from_ident(qt_ident).to_string(),
cxx_file_stem: parser.cxx_file_stem.clone(),
namespace: parser.cxx_qt_data.namespace.clone(),
qobjects: parser
.cxx_qt_data
Expand Down Expand Up @@ -75,7 +64,24 @@ mod tests {
let parser = Parser::from(module).unwrap();

let cpp = GeneratedCppBlocks::from(&parser).unwrap();
assert_eq!(cpp.cxx_stem, "my_object");
assert_eq!(cpp.cxx_file_stem, "ffi");
assert_eq!(cpp.namespace, "");
assert_eq!(cpp.qobjects.len(), 1);
}

#[test]
fn test_generated_cpp_blocks_cxx_file_stem() {
let module: ItemMod = tokens_to_syn(quote! {
#[cxx_qt::bridge(cxx_file_stem = "my_object")]
mod ffi {
#[cxx_qt::qobject]
struct MyObject;
}
});
let parser = Parser::from(module).unwrap();

let cpp = GeneratedCppBlocks::from(&parser).unwrap();
assert_eq!(cpp.cxx_file_stem, "my_object");
assert_eq!(cpp.namespace, "");
assert_eq!(cpp.qobjects.len(), 1);
}
Expand Down
1 change: 0 additions & 1 deletion crates/cxx-qt-gen/src/generator/naming/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
pub mod invokable;
pub mod module;
pub mod namespace;
pub mod property;
pub mod qobject;
Expand Down
27 changes: 0 additions & 27 deletions crates/cxx-qt-gen/src/generator/naming/module.rs

This file was deleted.

45 changes: 31 additions & 14 deletions crates/cxx-qt-gen/src/generator/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ pub mod property;
pub mod qobject;
pub mod signals;

use crate::generator::{naming::module::cxx_stem_from_ident, rust::qobject::GeneratedRustQObject};
use crate::generator::rust::qobject::GeneratedRustQObject;
use crate::parser::Parser;
use quote::quote;
use syn::{spanned::Spanned, Error, Item, ItemMod, Result};
use syn::{Item, ItemMod, Result};

/// Representation of the generated Rust code for a QObject
pub struct GeneratedRustBlocks {
Expand Down Expand Up @@ -48,17 +48,7 @@ impl GeneratedRustBlocks {

/// Generate the include line for this parsed block
fn generate_include(parser: &Parser) -> Result<Item> {
// TODO: for now the cxx stem comes from the first QObject name
// but later this may come from the module or file so would then have
// a field on the cxx_qt_data
if parser.cxx_qt_data.qobjects.len() != 1 {
return Err(Error::new(
parser.passthrough_module.span(),
"Only one QObject is currently supported in the ItemMod.",
));
}
let (qt_ident, _) = parser.cxx_qt_data.qobjects.iter().take(1).next().unwrap();
let import_path = format!("cxx-qt-gen/{}.cxxqt.h", cxx_stem_from_ident(qt_ident));
let import_path = format!("cxx-qt-gen/{}.cxxqt.h", parser.cxx_file_stem);

syn::parse2(quote! {
unsafe extern "C++" {
Expand Down Expand Up @@ -91,7 +81,7 @@ mod tests {
&rust.cxx_mod_contents[0],
quote! {
unsafe extern "C++" {
include!("cxx-qt-gen/my_object.cxxqt.h");
include!("cxx-qt-gen/ffi.cxxqt.h");
}
},
);
Expand Down Expand Up @@ -139,4 +129,31 @@ mod tests {
assert_eq!(rust.namespace, "cxx_qt");
assert_eq!(rust.qobjects.len(), 1);
}

#[test]
fn test_generated_rust_blocks_cxx_file_stem() {
let module: ItemMod = tokens_to_syn(quote! {
#[cxx_qt::bridge(cxx_file_stem = "my_object")]
mod ffi {
#[cxx_qt::qobject]
struct MyObject;
}
});
let parser = Parser::from(module).unwrap();

let rust = GeneratedRustBlocks::from(&parser).unwrap();
assert_eq!(rust.cxx_mod.content.unwrap().1.len(), 0);
assert_eq!(rust.cxx_mod_contents.len(), 1);
assert_tokens_eq(
&rust.cxx_mod_contents[0],
quote! {
unsafe extern "C++" {
include!("cxx-qt-gen/my_object.cxxqt.h");
}
},
);
assert_eq!(rust.cxx_qt_mod_contents.len(), 0);
assert_eq!(rust.namespace, "");
assert_eq!(rust.qobjects.len(), 1);
}
}
28 changes: 19 additions & 9 deletions crates/cxx-qt-gen/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,36 @@ pub struct Parser {
pub passthrough_module: ItemMod,
/// Any CXX-Qt data that needs generation later
pub cxx_qt_data: ParsedCxxQtData,
/// The stem of the file that the CXX headers for this module will be generated into
pub cxx_file_stem: String,
}

impl Parser {
/// Constructs a Parser object from a given [syn::ItemMod] block
pub fn from(mut module: ItemMod) -> Result<Self> {
let mut cxx_qt_data = ParsedCxxQtData::default();
let mut others = vec![];
let mut cxx_file_stem = module.ident.to_string();

// Remove the cxx_qt::bridge attribute
if let Some(index) = attribute_find_path(&module.attrs, &["cxx_qt", "bridge"]) {
// Parse any namespace in the cxx_qt::bridge macro
cxx_qt_data.namespace = if let Some(lit_str) = attribute_tokens_to_map::<Ident, LitStr>(
let attr_map = attribute_tokens_to_map::<Ident, LitStr>(
&module.attrs[index],
AttributeDefault::None,
)?
.get(&quote::format_ident!("namespace"))
{
lit_str.value()
} else {
"".to_owned()
};
)?;
// Parse any namespace in the cxx_qt::bridge macro
cxx_qt_data.namespace =
if let Some(lit_str) = attr_map.get(&quote::format_ident!("namespace")) {
lit_str.value()
} else {
"".to_owned()
};

// Parse any custom file stem
if let Some(stem) = attr_map.get(&quote::format_ident!("cxx_file_stem")) {
cxx_file_stem = stem.value();
}

module.attrs.remove(index);
} else {
return Err(Error::new(
Expand Down Expand Up @@ -87,6 +96,7 @@ impl Parser {
Ok(Self {
passthrough_module: module,
cxx_qt_data,
cxx_file_stem,
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/writer/cpp/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ pub fn write_cpp_header(generated: &GeneratedCppBlocks) -> String {
}}
{forward_declare}
#include "cxx-qt-gen/{cxx_stem}.cxx.h"
#include "cxx-qt-gen/{cxx_file_stem}.cxx.h"
{qobjects}
"#,
cxx_stem = generated.cxx_stem,
cxx_file_stem = generated.cxx_file_stem,
forward_declare = forward_declare(generated).join("\n"),
qobjects = qobjects_header(generated).join("\n"),
}
Expand Down
16 changes: 8 additions & 8 deletions crates/cxx-qt-gen/src/writer/cpp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ mod tests {
/// Helper to create a GeneratedCppBlocks for testing
pub fn create_generated_cpp() -> GeneratedCppBlocks {
GeneratedCppBlocks {
cxx_stem: "cxx_stem".to_owned(),
cxx_file_stem: "cxx_file_stem".to_owned(),
namespace: "cxx_qt::my_object".to_owned(),
qobjects: vec![
GeneratedCppQObject {
Expand Down Expand Up @@ -149,7 +149,7 @@ mod tests {
/// Helper to create a GeneratedCppBlocks for testing with multiple qobjects
pub fn create_generated_cpp_multi_qobjects() -> GeneratedCppBlocks {
GeneratedCppBlocks {
cxx_stem: "cxx_stem".to_owned(),
cxx_file_stem: "cxx_file_stem".to_owned(),
namespace: "cxx_qt".to_owned(),
qobjects: vec![
GeneratedCppQObject {
Expand Down Expand Up @@ -254,7 +254,7 @@ mod tests {
using MyObjectCxxQtThread = rust::cxxqtlib1::CxxQtThread<MyObject>;
} // namespace cxx_qt::my_object
#include "cxx-qt-gen/cxx_stem.cxx.h"
#include "cxx-qt-gen/cxx_file_stem.cxx.h"
namespace cxx_qt::my_object {
class MyObject : public QStringListModel
Expand Down Expand Up @@ -326,7 +326,7 @@ mod tests {
using SecondObjectCxxQtThread = rust::cxxqtlib1::CxxQtThread<SecondObject>;
} // namespace cxx_qt
#include "cxx-qt-gen/cxx_stem.cxx.h"
#include "cxx-qt-gen/cxx_file_stem.cxx.h"
namespace cxx_qt {
class FirstObject : public QStringListModel
Expand Down Expand Up @@ -425,7 +425,7 @@ mod tests {
using MyObjectCxxQtThread = rust::cxxqtlib1::CxxQtThread<MyObject>;
#include "cxx-qt-gen/cxx_stem.cxx.h"
#include "cxx-qt-gen/cxx_file_stem.cxx.h"
class MyObject : public QStringListModel
Expand Down Expand Up @@ -477,7 +477,7 @@ mod tests {
/// Helper for the expected source
pub fn expected_source() -> &'static str {
indoc! {r#"
#include "cxx-qt-gen/cxx_stem.cxxqt.h"
#include "cxx-qt-gen/cxx_file_stem.cxxqt.h"
namespace cxx_qt::my_object {
Expand Down Expand Up @@ -565,7 +565,7 @@ mod tests {
/// Helper for the expected source with multiple QObjects
pub fn expected_source_multi_qobjects() -> &'static str {
indoc! {r#"
#include "cxx-qt-gen/cxx_stem.cxxqt.h"
#include "cxx-qt-gen/cxx_file_stem.cxxqt.h"
namespace cxx_qt {
Expand Down Expand Up @@ -685,7 +685,7 @@ mod tests {
/// Helper for the expected header with no namespace
pub fn expected_source_no_namespace() -> &'static str {
indoc! {r#"
#include "cxx-qt-gen/cxx_stem.cxxqt.h"
#include "cxx-qt-gen/cxx_file_stem.cxxqt.h"
Expand Down
4 changes: 2 additions & 2 deletions crates/cxx-qt-gen/src/writer/cpp/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ fn qobjects_source(generated: &GeneratedCppBlocks) -> Vec<String> {
/// For a given GeneratedCppBlocks write this into a C++ source
pub fn write_cpp_source(generated: &GeneratedCppBlocks) -> String {
formatdoc! {r#"
#include "cxx-qt-gen/{cxx_stem}.cxxqt.h"
#include "cxx-qt-gen/{cxx_file_stem}.cxxqt.h"
{qobjects}
"#,
cxx_stem = generated.cxx_stem,
cxx_file_stem = generated.cxx_file_stem,
qobjects = qobjects_source(generated).join("\n"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_inputs/passthrough_and_naming.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[attrA]
#[cxx_qt::bridge(namespace = "cxx_qt::my_object")]
#[cxx_qt::bridge(namespace = "cxx_qt::my_object", cxx_file_stem = "my_object")]
#[attrB]
pub mod ffi {
// ItemConst
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/invokables.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "cxx-qt-gen/my_object.cxxqt.h"
#include "cxx-qt-gen/ffi.cxxqt.h"

namespace cxx_qt::my_object {

Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/invokables.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MyObject;
using MyObjectCxxQtThread = rust::cxxqtlib1::CxxQtThread<MyObject>;
} // namespace cxx_qt::my_object

#include "cxx-qt-gen/my_object.cxx.h"
#include "cxx-qt-gen/ffi.cxx.h"

namespace cxx_qt::my_object {
class MyObject : public QObject
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/invokables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod ffi {
}

unsafe extern "C++" {
include!("cxx-qt-gen/my_object.cxxqt.h");
include!("cxx-qt-gen/ffi.cxxqt.h");
}

unsafe extern "C++" {
Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/properties.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "cxx-qt-gen/my_object.cxxqt.h"
#include "cxx-qt-gen/ffi.cxxqt.h"

namespace cxx_qt::my_object {

Expand Down
2 changes: 1 addition & 1 deletion crates/cxx-qt-gen/test_outputs/properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MyObject;
using MyObjectCxxQtThread = rust::cxxqtlib1::CxxQtThread<MyObject>;
} // namespace cxx_qt::my_object

#include "cxx-qt-gen/my_object.cxx.h"
#include "cxx-qt-gen/ffi.cxx.h"

namespace cxx_qt::my_object {
class MyObject : public QObject
Expand Down
Loading

0 comments on commit d5f4f45

Please sign in to comment.