Skip to content

Commit

Permalink
cxx-qt-gen: store module ident in parser and simplify populating mapping
Browse files Browse the repository at this point in the history
This also simplifies extern "C++Qt" support later.

Related to #577
  • Loading branch information
ahayzen-kdab authored and Be-ing committed Jul 26, 2023
1 parent d3643ec commit 9cbc1ea
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 65 deletions.
88 changes: 37 additions & 51 deletions crates/cxx-qt-gen/src/parser/cxxqtdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ impl ParsedCxxMappings {
}
}

#[derive(Default)]
pub struct ParsedCxxQtData {
/// Mappings for CXX types when used in C++
pub cxx_mappings: ParsedCxxMappings,
Expand All @@ -62,9 +61,22 @@ pub struct ParsedCxxQtData {
pub qobjects: BTreeMap<Ident, ParsedQObject>,
/// The namespace of the CXX-Qt module
pub namespace: String,
/// The ident of the module, used for mappings
pub module_ident: Ident,
}

impl ParsedCxxQtData {
/// Create a ParsedCxxQtData from a given module and namespace
pub fn new(module_ident: Ident, namespace: String) -> Self {
Self {
cxx_mappings: ParsedCxxMappings::default(),
qualified_mappings: BTreeMap::<Ident, Path>::default(),
qobjects: BTreeMap::<Ident, ParsedQObject>::default(),
module_ident,
namespace,
}
}

/// Find the QObjects within the module and add into the qobjects BTreeMap
pub fn find_qobject_types(&mut self, items: &[Item]) -> Result<()> {
for item in items {
Expand Down Expand Up @@ -107,19 +119,16 @@ impl ParsedCxxQtData {
///
/// We need to know this as it affects the type name used in the C++ generation
/// And it is used to create the qualified Rust name
pub fn populate_mappings_from_item(
&mut self,
item: &Item,
bridge_namespace: &str,
module_ident: &Ident,
) -> Result<()> {
pub fn populate_mappings_from_item(&mut self, item: &Item) -> Result<()> {
let bridge_namespace = self.namespace.clone();

// Consider if shared types have mappings
match item {
Item::Enum(item) => {
self.populate_mappings(&item.ident, &item.attrs, bridge_namespace, module_ident)?;
self.populate_mappings(&item.ident, &item.attrs, &bridge_namespace)?;
}
Item::Struct(item) => {
self.populate_mappings(&item.ident, &item.attrs, bridge_namespace, module_ident)?;
self.populate_mappings(&item.ident, &item.attrs, &bridge_namespace)?;
}
_others => {}
}
Expand All @@ -136,12 +145,7 @@ impl ParsedCxxQtData {

// Read each of the types in the mod (type A;)
for foreign_type in foreign_mod_to_foreign_item_types(foreign_mod)? {
self.populate_mappings(
&foreign_type.ident,
&foreign_type.attrs,
&block_namespace,
module_ident,
)?;
self.populate_mappings(&foreign_type.ident, &foreign_type.attrs, &block_namespace)?;
}
}

Expand All @@ -154,7 +158,6 @@ impl ParsedCxxQtData {
ident: &Ident,
attrs: &[Attribute],
parent_namespace: &str,
module_ident: &Ident,
) -> Result<()> {
// Retrieve the namespace for the type itself if there is one
let namespace = if let Some(index) = attribute_find_path(attrs, &["namespace"]) {
Expand Down Expand Up @@ -188,6 +191,7 @@ impl ParsedCxxQtData {
} else {
ident.clone()
};
let module_ident = &self.module_ident;
self.qualified_mappings
.insert(ident.clone(), parse_quote! { #module_ident::#rust_ident });

Expand Down Expand Up @@ -318,7 +322,7 @@ mod tests {

/// Creates a ParsedCxxQtData with a QObject definition already found
fn create_parsed_cxx_qt_data() -> ParsedCxxQtData {
let mut cxx_qt_data = ParsedCxxQtData::default();
let mut cxx_qt_data = ParsedCxxQtData::new(format_ident!("ffi"), "".to_string());
cxx_qt_data
.qobjects
.insert(qobject_ident(), create_parsed_qobject());
Expand All @@ -327,7 +331,7 @@ mod tests {

#[test]
fn test_find_qobjects_one_qobject() {
let mut cxx_qt_data = ParsedCxxQtData::default();
let mut cxx_qt_data = ParsedCxxQtData::new(format_ident!("ffi"), "".to_string());

let module: ItemMod = parse_quote! {
mod module {
Expand All @@ -347,7 +351,7 @@ mod tests {

#[test]
fn test_find_qobjects_multiple_qobject() {
let mut cxx_qt_data = ParsedCxxQtData::default();
let mut cxx_qt_data = ParsedCxxQtData::new(format_ident!("ffi"), "".to_string());

let module: ItemMod = parse_quote! {
mod module {
Expand All @@ -372,10 +376,8 @@ mod tests {

#[test]
fn test_find_qobjects_namespace() {
let mut cxx_qt_data = ParsedCxxQtData {
namespace: "bridge_namespace".to_owned(),
..Default::default()
};
let mut cxx_qt_data =
ParsedCxxQtData::new(format_ident!("ffi"), "bridge_namespace".to_string());

let module: ItemMod = parse_quote! {
mod module {
Expand Down Expand Up @@ -412,7 +414,7 @@ mod tests {

#[test]
fn test_find_qobjects_no_macro() {
let mut cxx_qt_data = ParsedCxxQtData::default();
let mut cxx_qt_data = ParsedCxxQtData::new(format_ident!("ffi"), "".to_string());

let module: ItemMod = parse_quote! {
mod module {
Expand Down Expand Up @@ -551,9 +553,7 @@ mod tests {
type A;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert!(cxx_qt_data.cxx_mappings.cxx_names.is_empty());

assert_eq!(cxx_qt_data.qualified_mappings.len(), 1);
Expand All @@ -576,9 +576,7 @@ mod tests {
type A;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 1);
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.get("A").unwrap(), "B");

Expand All @@ -602,9 +600,7 @@ mod tests {
type A = C;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 1);
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.get("A").unwrap(), "B");

Expand All @@ -621,6 +617,7 @@ mod tests {
#[test]
fn test_cxx_mappings_cxx_name_namespace_bridge() {
let mut cxx_qt_data = create_parsed_cxx_qt_data();
cxx_qt_data.namespace = "bridge_namespace".to_owned();

let item: Item = parse_quote! {
extern "C++" {
Expand All @@ -630,9 +627,7 @@ mod tests {
type B;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "bridge_namespace", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 1);
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.get("B").unwrap(), "C");

Expand Down Expand Up @@ -666,6 +661,7 @@ mod tests {
#[test]
fn test_cxx_mappings_cxx_name_namespace_items() {
let mut cxx_qt_data = create_parsed_cxx_qt_data();
cxx_qt_data.namespace = "namespace".to_owned();

let item: Item = parse_quote! {
#[namespace = "extern_namespace"]
Expand All @@ -677,9 +673,7 @@ mod tests {
}
};
// Also ensure item namespace is chosen instead of bridge namespace
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "namespace", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 0);

assert_eq!(cxx_qt_data.cxx_mappings.namespaces.len(), 2);
Expand Down Expand Up @@ -724,9 +718,7 @@ mod tests {
type C;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 2);
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.get("A").unwrap(), "B");
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.get("C").unwrap(), "D");
Expand Down Expand Up @@ -770,9 +762,7 @@ mod tests {
}
};

assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 1);
assert_eq!(
cxx_qt_data.cxx_mappings.cxx_names.get("EnumA").unwrap(),
Expand Down Expand Up @@ -807,9 +797,7 @@ mod tests {
}
};

assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert_eq!(cxx_qt_data.cxx_mappings.cxx_names.len(), 1);
assert_eq!(
cxx_qt_data.cxx_mappings.cxx_names.get("StructA").unwrap(),
Expand Down Expand Up @@ -842,9 +830,7 @@ mod tests {
type A;
}
};
assert!(cxx_qt_data
.populate_mappings_from_item(&item, "", &format_ident!("ffi"))
.is_ok());
assert!(cxx_qt_data.populate_mappings_from_item(&item).is_ok());
assert!(cxx_qt_data.cxx_mappings.cxx_names.is_empty());

assert_eq!(cxx_qt_data.qualified_mappings.len(), 1);
Expand Down
22 changes: 8 additions & 14 deletions crates/cxx-qt-gen/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct Parser {
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 namespace = "".to_owned();
let mut others = vec![];
let mut cxx_file_stem = module.ident.to_string();

Expand All @@ -44,13 +44,11 @@ impl Parser {
&module.attrs[index],
AttributeDefault::None,
)?;

// 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()
};
if let Some(lit_str) = attr_map.get(&quote::format_ident!("namespace")) {
namespace = lit_str.value();
}

// Parse any custom file stem
if let Some(stem) = attr_map.get(&quote::format_ident!("cxx_file_stem")) {
Expand All @@ -65,10 +63,10 @@ impl Parser {
));
}

let mut cxx_qt_data = ParsedCxxQtData::new(module.ident.clone(), namespace);

// Check that there are items in the module
if let Some(mut items) = module.content {
let bridge_namespace = cxx_qt_data.namespace.clone();

// Find any QObject structs
cxx_qt_data.find_qobject_types(&items.1)?;

Expand All @@ -78,11 +76,7 @@ impl Parser {
// qobject. Otherwise return them to be added to other
if let Some(other) = cxx_qt_data.parse_cxx_qt_item(item)? {
// Load any CXX name mappings
cxx_qt_data.populate_mappings_from_item(
&other,
&bridge_namespace,
&module.ident,
)?;
cxx_qt_data.populate_mappings_from_item(&other)?;

// Unknown item so add to the other list
others.push(other);
Expand Down

0 comments on commit 9cbc1ea

Please sign in to comment.