From dd2934338bd022ca573217a5a57cab8e10e5ae4b Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Wed, 26 Feb 2025 16:57:04 +0000 Subject: [PATCH] Eliminate "Use" type. This was no longer necessary or sensible. --- .../src/conversion/codegen_rs/fun_codegen.rs | 41 ++--- engine/src/conversion/codegen_rs/mod.rs | 153 +++++------------- engine/src/conversion/codegen_rs/utils.rs | 29 ++++ 3 files changed, 87 insertions(+), 136 deletions(-) create mode 100644 engine/src/conversion/codegen_rs/utils.rs diff --git a/engine/src/conversion/codegen_rs/fun_codegen.rs b/engine/src/conversion/codegen_rs/fun_codegen.rs index a73ef973e..9e00da576 100644 --- a/engine/src/conversion/codegen_rs/fun_codegen.rs +++ b/engine/src/conversion/codegen_rs/fun_codegen.rs @@ -23,7 +23,8 @@ use super::{ function_wrapper_rs::RustParamConversion, maybe_unsafes_to_tokens, unqualify::{unqualify_params_minisyn, unqualify_ret_type}, - ImplBlockDetails, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, Use, + utils::generate_cxx_use_stmt, + ImplBlockDetails, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, }; use crate::{ conversion::{ @@ -34,7 +35,7 @@ use crate::{ api::UnsafetyNeeded, }, minisyn::{minisynize_vec, FnArg}, - types::{Namespace, QualifiedName}, + types::QualifiedName, }; use crate::{ conversion::{api::FuncToConvert, codegen_rs::lifetime::add_explicit_lifetime_if_necessary}, @@ -85,7 +86,7 @@ impl UnsafetyNeeded { } pub(super) fn gen_function( - ns: &Namespace, + name: &QualifiedName, fun: FuncToConvert, analysis: FnAnalysis, non_pod_types: &HashSet, @@ -132,7 +133,7 @@ pub(super) fn gen_function( &ret_conversion, ); - let mut materializations = Vec::new(); + let mut output_mod_items = Vec::new(); if analysis.rust_wrapper_needed { match kind { @@ -160,27 +161,15 @@ pub(super) fn gen_function( } _ => { // Generate plain old function - materializations.push(Use::Custom(Box::new(fn_generator.generate_function_impl()))); + output_mod_items.push(fn_generator.generate_function_impl()); } } - } - - // This and the 'if let' can be simplified. TODO. - let materialization = match kind { - FnKind::Method { .. } | FnKind::TraitMethod { .. } => None, - FnKind::Function => match analysis.rust_rename_strategy { - _ if analysis.rust_wrapper_needed => { - assert!(!materializations.is_empty()); - None - } - RustRenameStrategy::RenameInOutputMod(ref alias) => { - Some(Use::UsedFromCxxBridgeWithAlias(alias.clone().into())) - } - _ => Some(Use::UsedFromCxxBridge), - }, - }; - if let Some(materialization) = materialization { - materializations.push(materialization); + } else if matches!(kind, FnKind::Function) { + let alias = match analysis.rust_rename_strategy { + RustRenameStrategy::RenameInOutputMod(ref alias) => Some(&alias.0), + _ => None, + }; + output_mod_items.push(generate_cxx_use_stmt(name, alias)); } if let Some(cpp_call_name) = cpp_call_name { @@ -204,10 +193,10 @@ pub(super) fn gen_function( let ret_type = unqualify_ret_type(ret_type.into_owned()); // And we need to make an attribute for the namespace that the function // itself is in. - let namespace_attr = if ns.is_empty() || wrapper_function_needed { + let namespace_attr = if name.get_namespace().is_empty() || wrapper_function_needed { Vec::new() } else { - let namespace_string = ns.to_string(); + let namespace_string = name.get_namespace().to_string(); Attribute::parse_outer .parse2(quote!( #[namespace = #namespace_string] @@ -226,7 +215,7 @@ pub(super) fn gen_function( extern_c_mod_items: vec![extern_c_mod_item], impl_entry, trait_impl_entry, - materializations, + output_mod_items, ..Default::default() } } diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs index 8a7da53fb..e0c0a1308 100644 --- a/engine/src/conversion/codegen_rs/mod.rs +++ b/engine/src/conversion/codegen_rs/mod.rs @@ -12,6 +12,7 @@ mod impl_item_creator; mod lifetime; mod namespace_organizer; pub(crate) mod unqualify; +mod utils; use indexmap::map::IndexMap as HashMap; use indexmap::set::IndexSet as HashSet; @@ -24,6 +25,7 @@ use syn::{ parse_quote, punctuated::Punctuated, token::Comma, Attribute, Expr, FnArg, ForeignItem, ForeignItemFn, Ident, ImplItem, Item, ItemForeignMod, ItemMod, TraitItem, Type, TypePath, }; +use utils::{find_output_mod_root, generate_cxx_use_stmt}; use crate::{ conversion::codegen_rs::unqualify::{unqualify_params, unqualify_ret_type}, @@ -65,23 +67,6 @@ struct TraitImplBlockDetails { key: TraitImplSignature, } -/// Whether and how this item should be exposed in the mods constructed -/// for actual end-user use. -#[derive(Clone)] -enum Use { - /// Uses from cxx::bridge - UsedFromCxxBridge, - /// 'use' points to cxx::bridge with a different name - UsedFromCxxBridgeWithAlias(Ident), - /// 'use' directive points to bindgen - UsedFromBindgen, - /// Do not expose the original item from bindgen, but instead create - /// an opaque struct. - CreateOpaqueTypeWrappingBindgen { num_generics: usize }, - /// Some kind of custom item - Custom(Box), -} - fn get_string_items() -> Vec { [ Item::Trait(parse_quote! { @@ -326,20 +311,8 @@ impl<'a> RsCodeGenerator<'a> { ns_entries: &NamespaceEntries<(QualifiedName, RsCodegenResult)>, output_items: &mut Vec, ) { - for (name, codegen) in ns_entries.entries() { - output_items.extend(codegen.materializations.iter().map(|materialization| { - match materialization { - Use::UsedFromCxxBridgeWithAlias(ref alias) => { - Self::generate_cxx_use_stmt(name, Some(alias)) - } - Use::UsedFromCxxBridge => Self::generate_cxx_use_stmt(name, None), - Use::UsedFromBindgen => Self::generate_bindgen_use_stmt(name), - Use::Custom(item) => *item.clone(), - Use::CreateOpaqueTypeWrappingBindgen { num_generics } => { - Self::generate_opaque_type(name, *num_generics) - } - } - })); + for (_name, codegen) in ns_entries.entries() { + output_items.extend(codegen.output_mod_items.iter().cloned()); } let mut impl_entries_by_type: HashMap<_, Vec<_>> = HashMap::new(); @@ -416,17 +389,18 @@ impl<'a> RsCodeGenerator<'a> { fn #make_string_name(str_: &str) -> UniquePtr; ))], global_items: get_string_items(), - materializations: vec![Use::UsedFromCxxBridgeWithAlias( - make_ident("make_string").into(), + output_mod_items: vec![generate_cxx_use_stmt( + &name, + Some(&make_ident("make_string").0), )], ..Default::default() } } Api::Function { fun, analysis, .. } => { - gen_function(name.get_namespace(), *fun, analysis, non_pod_types) + gen_function(&name, *fun, analysis, non_pod_types) } Api::Const { .. } | Api::Typedef { .. } => RsCodegenResult { - materializations: vec![Use::UsedFromBindgen], + output_mod_items: vec![Self::generate_bindgen_use_stmt(&name)], ..Default::default() }, Api::Struct { @@ -499,9 +473,7 @@ impl<'a> RsCodeGenerator<'a> { global_items: vec![parse_quote! { use super::#path; }], - materializations: vec![Use::Custom(Box::new( - parse_quote! {#[allow(unused_imports)] use super::#id;}, - ))], + output_mod_items: vec![parse_quote! {#[allow(unused_imports)] use super::#id;}], extern_rust_mod_items: vec![parse_quote! { type #id; }], @@ -578,7 +550,7 @@ impl<'a> RsCodeGenerator<'a> { let cpp_id = full_cpp.get_final_ident(); let mut global_items = Vec::new(); let relinquish_ownership_call = sub.cpp_remove_ownership(); - let mut per_mod_items: Vec = vec![ + let mut output_mod_items: Vec = vec![ parse_quote! { pub use cxxbridge::#cpp_id; }, @@ -627,7 +599,7 @@ impl<'a> RsCodeGenerator<'a> { }) .collect(); if !methods_impls.is_empty() { - per_mod_items.push(parse_quote! { + output_mod_items.push(parse_quote! { #[allow(non_snake_case)] impl #supers for super::super::#id { #(#methods_impls)* @@ -636,7 +608,7 @@ impl<'a> RsCodeGenerator<'a> { } } if generate_peer_constructor { - per_mod_items.push(parse_quote! { + output_mod_items.push(parse_quote! { impl autocxx::subclass::CppPeerConstructor<#cpp_id> for super::super::#id { fn make_peer(&mut self, peer_holder: autocxx::subclass::CppSubclassRustPeerHolder) -> cxx::UniquePtr<#cpp_path> { use autocxx::moveit::Emplace; @@ -659,7 +631,7 @@ impl<'a> RsCodeGenerator<'a> { extern_c_mod_items.push(parse_quote! { fn #as_unique_ptr_id(u: UniquePtr<#cpp_id>) -> UniquePtr<#super_cxxxbridge_id>; }); - per_mod_items.push(parse_quote! { + output_mod_items.push(parse_quote! { impl AsRef<#super_path> for super::super::#id { fn as_ref(&self) -> &cxxbridge::#super_cxxxbridge_id { use autocxx::subclass::CppSubclass; @@ -668,7 +640,7 @@ impl<'a> RsCodeGenerator<'a> { } }); // TODO it would be nice to impl AsMut here but pin prevents us - per_mod_items.push(parse_quote! { + output_mod_items.push(parse_quote! { impl super::super::#id { pub fn pin_mut(&mut self) -> ::core::pin::Pin<&mut cxxbridge::#super_cxxxbridge_id> { use autocxx::subclass::CppSubclass; @@ -677,7 +649,7 @@ impl<'a> RsCodeGenerator<'a> { } }); let rs_as_unique_ptr_id = make_ident(format!("as_{super_name}_unique_ptr")); - per_mod_items.push(parse_quote! { + output_mod_items.push(parse_quote! { impl super::super::#id { pub fn #rs_as_unique_ptr_id(u: cxx::UniquePtr<#cpp_id>) -> cxx::UniquePtr { cxxbridge::#as_unique_ptr_id(u) @@ -691,17 +663,13 @@ impl<'a> RsCodeGenerator<'a> { Box::new(#holder(me.0.relinquish_ownership())) } }); - let materializations = per_mod_items - .into_iter() - .map(|item| Use::Custom(Box::new(item))) - .collect(); RsCodegenResult { extern_c_mod_items, // For now we just assume we can't keep subclasses in vectors, but we can put them in // smart pointers. // That's the reason for the 'false' and 'true' bridge_items: create_impl_items(&cpp_id, false, true, self.config), - materializations, + output_mod_items, global_items, extern_rust_mod_items: vec![ parse_quote! { @@ -794,14 +762,14 @@ impl<'a> RsCodeGenerator<'a> { where F: FnOnce() -> Option<(Item, Vec)>, { - let mut materializations = vec![match type_kind { - TypeKind::Pod => Use::UsedFromBindgen, - TypeKind::Abstract => Use::UsedFromCxxBridge, - _ => Use::CreateOpaqueTypeWrappingBindgen { num_generics }, + let mut output_mod_items = vec![match type_kind { + TypeKind::Pod => Self::generate_bindgen_use_stmt(name), + TypeKind::Abstract => generate_cxx_use_stmt(name, None), + _ => Self::generate_opaque_type(name, num_generics), }]; Self::add_superclass_stuff_to_type( name, - &mut materializations, + &mut output_mod_items, associated_methods.get(name), ); let orig_item = item_creator(); @@ -842,21 +810,17 @@ impl<'a> RsCodeGenerator<'a> { // Still generate the type as emitted by bindgen, // but don't attempt to tell cxx about it RsCodegenResult { - materializations, + output_mod_items, ..Default::default() } } else { - materializations.extend( - self.generate_extern_type_impl(type_kind, name) - .into_iter() - .map(|m| Use::Custom(Box::new(m))), - ); + output_mod_items.append(&mut self.generate_extern_type_impl(type_kind, name)); RsCodegenResult { bridge_items: create_impl_items(&id, movable, destroyable, self.config), extern_c_mod_items: vec![ self.generate_cxxbridge_type(name, true, doc_attrs) ], - materializations, + output_mod_items, ..Default::default() } } @@ -873,7 +837,7 @@ impl<'a> RsCodeGenerator<'a> { self.generate_cxxbridge_type(name, false, doc_attrs) ], bridge_items: create_impl_items(&id, movable, destroyable, self.config), - materializations, + output_mod_items, ..Default::default() } } @@ -883,7 +847,7 @@ impl<'a> RsCodeGenerator<'a> { fn add_superclass_stuff_to_type( name: &QualifiedName, - materializations: &mut Vec, + output_mod_items: &mut Vec, methods: Option<&Vec>, ) { if let Some(methods) = methods { @@ -928,25 +892,25 @@ impl<'a> RsCodeGenerator<'a> { let supers_name = SubclassName::get_supers_trait_name(name).get_final_ident(); let methods_name = SubclassName::get_methods_trait_name(name).get_final_ident(); if !supers.is_empty() { - materializations.push(Use::Custom(Box::new(parse_quote! { + output_mod_items.push(parse_quote! { #[allow(non_snake_case)] pub trait #supers_name { #(#supers)* } - }))); - materializations.push(Use::Custom(Box::new(parse_quote! { + }); + output_mod_items.push(parse_quote! { #[allow(non_snake_case)] pub trait #methods_name : #supers_name { #(#mains)* } - }))); + }); } else { - materializations.push(Use::Custom(Box::new(parse_quote! { + output_mod_items.push(parse_quote! { #[allow(non_snake_case)] pub trait #methods_name { #(#mains)* } - }))); + }); } } } @@ -970,9 +934,7 @@ impl<'a> RsCodeGenerator<'a> { } RsCodegenResult { extern_c_mod_items: vec![self.generate_cxxbridge_type(name, true, Vec::new())], - materializations: vec![Use::Custom(Box::new( - parse_quote! { pub use #rust_path as #name_final; }, - ))], + output_mod_items: vec![parse_quote! { pub use #rust_path as #name_final; }], ..Default::default() } } @@ -982,13 +944,13 @@ impl<'a> RsCodeGenerator<'a> { /// generated. fn generate_error_entry(err: ConvertErrorFromCpp, ctx: ErrorContext) -> RsCodegenResult { let err = format!(" autocxx bindings couldn't be generated: {err}"); - let (impl_entry, namespaced_item) = match ctx.into_type() { + let (impl_entry, output_mod_items) = match ctx.into_type() { ErrorContextType::Item(id) | ErrorContextType::SanitizedItem(id) => ( None, - Some(parse_quote! { + vec![parse_quote! { #[doc = #err] pub struct #id; - }), + }], ), ErrorContextType::Method { self_ty, method } => ( Some(Box::new(ImplBlockDetails { @@ -999,39 +961,18 @@ impl<'a> RsCodeGenerator<'a> { }, ty: parse_quote! { #self_ty }, })), - None, + vec![], ), }; - // The above code can be simplified to construct materializations - // in all cases. - let materializations = namespaced_item - .into_iter() - .map(|item| Use::Custom(Box::new(item))) - .collect(); RsCodegenResult { impl_entry, - materializations, + output_mod_items, ..Default::default() } } - fn generate_cxx_use_stmt(name: &QualifiedName, alias: Option<&Ident>) -> Item { - let segs = Self::find_output_mod_root(name.get_namespace()) - .chain(std::iter::once(make_ident("cxxbridge"))) - .chain(std::iter::once(name.get_final_ident())); - Item::Use(match alias { - None => parse_quote! { - pub use #(#segs)::*; - }, - Some(alias) => parse_quote! { - pub use #(#segs)::* as #alias; - }, - }) - } - fn generate_bindgen_use_stmt(name: &QualifiedName) -> Item { - let segs = - Self::find_output_mod_root(name.get_namespace()).chain(name.get_bindgen_path_idents()); + let segs = find_output_mod_root(name.get_namespace()).chain(name.get_bindgen_path_idents()); Item::Use(parse_quote! { #[allow(unused_imports)] pub use #(#segs)::*; @@ -1039,8 +980,7 @@ impl<'a> RsCodeGenerator<'a> { } fn generate_opaque_type(name: &QualifiedName, num_generics: usize) -> Item { - let segs = - Self::find_output_mod_root(name.get_namespace()).chain(name.get_bindgen_path_idents()); + let segs = find_output_mod_root(name.get_namespace()).chain(name.get_bindgen_path_idents()); let final_name = name.get_final_ident().0; let generics = (0usize..usize::MAX) @@ -1135,10 +1075,6 @@ impl<'a> RsCodeGenerator<'a> { } ForeignItem::Verbatim(for_extern_c_ts) } - - fn find_output_mod_root(ns: &Namespace) -> impl Iterator { - std::iter::repeat(make_ident("super")).take(ns.depth()) - } } fn find_trivially_constructed_subclasses(apis: &ApiVec) -> HashSet { @@ -1208,11 +1144,8 @@ struct RsCodegenResult { global_items: Vec, impl_entry: Option>, trait_impl_entry: Option>, - /// Items that go into a per-namespace mod. - /// These items used to be primarily `use` statements which - /// is why this is a bit odd, but this boils down to another - /// `Vec`. - materializations: Vec, + /// Items that go into a per-namespace mod exposed to the user. + output_mod_items: Vec, } /// An [`Item`] that always needs to be in an unsafe block. diff --git a/engine/src/conversion/codegen_rs/utils.rs b/engine/src/conversion/codegen_rs/utils.rs new file mode 100644 index 000000000..56cec4d6d --- /dev/null +++ b/engine/src/conversion/codegen_rs/utils.rs @@ -0,0 +1,29 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syn::{parse_quote, Ident, Item}; + +use crate::types::{make_ident, Namespace, QualifiedName}; + +pub(super) fn generate_cxx_use_stmt(name: &QualifiedName, alias: Option<&Ident>) -> Item { + let segs = find_output_mod_root(name.get_namespace()) + .chain(std::iter::once(make_ident("cxxbridge"))) + .chain(std::iter::once(name.get_final_ident())); + Item::Use(match alias { + None => parse_quote! { + pub use #(#segs)::*; + }, + Some(alias) => parse_quote! { + pub use #(#segs)::* as #alias; + }, + }) +} + +pub(super) fn find_output_mod_root(ns: &Namespace) -> impl Iterator { + std::iter::repeat(make_ident("super")).take(ns.depth()) +}