diff --git a/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs b/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs index aa5b1b74f..73e521329 100644 --- a/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs +++ b/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs @@ -81,6 +81,24 @@ pub struct CcPrerequisites<'tcx> { #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum TemplateSpecialization<'tcx> { RsStdEnum(RsStdEnumTemplateSpecialization<'tcx>), + TraitImpl(TraitImplTemplateSpecialization), +} + +#[derive(Clone, Debug)] +pub struct TraitImplTemplateSpecialization { + pub self_ty_cc_name: TokenStream, + pub trait_impl: DefId, +} +impl PartialEq for TraitImplTemplateSpecialization { + fn eq(&self, other: &Self) -> bool { + self.trait_impl == other.trait_impl + } +} +impl Eq for TraitImplTemplateSpecialization {} +impl Hash for TraitImplTemplateSpecialization { + fn hash(&self, state: &mut H) { + self.trait_impl.hash(state); + } } #[derive(Clone, Debug)] @@ -92,11 +110,19 @@ pub struct RsStdEnumTemplateSpecializationCore<'tcx> { pub tag_type_cc: CcSnippet<'tcx>, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RsStdEnumTemplateSpecialization<'tcx> { pub core: RsStdEnumTemplateSpecializationCore<'tcx>, pub kind: TemplateSpecializationKind<'tcx>, } +impl std::fmt::Debug for RsStdEnumTemplateSpecialization<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RsStdEnumTemplateSpecialization") + .field("core", &self.core.self_ty_rs) + .field("kind", &self.kind) + .finish() + } +} impl PartialEq for RsStdEnumTemplateSpecialization<'_> { fn eq(&self, other: &Self) -> bool { diff --git a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs index 16eda77bd..eeb5d5382 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs @@ -3,12 +3,16 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception use crate::generate_function_thunk::replace_all_regions_with_static; -use crate::generate_struct_and_union::{generate_relocating_ctor, scalar_value_to_string}; -use arc_anyhow::Result; +use crate::generate_struct_and_union::{ + generate_associated_item, generate_relocating_ctor, has_type_or_const_vars, + scalar_value_to_string, +}; +use crate::generate_unsupported_def; +use arc_anyhow::{Error, Result}; use code_gen_utils::{escape_non_identifier_chars, CcInclude}; use database::code_snippet::{ ApiSnippets, CcPrerequisites, CcSnippet, FormattedTy, RsStdEnumTemplateSpecialization, - RsStdEnumTemplateSpecializationCore, TemplateSpecialization, + RsStdEnumTemplateSpecializationCore, TemplateSpecialization, TraitImplTemplateSpecialization, }; use database::{BindingsGenerator, TypeLocation}; use error_report::anyhow; @@ -19,6 +23,8 @@ use quote::{format_ident, quote}; use rustc_abi::VariantIdx; use rustc_middle::ty::layout::PrimitiveExt; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_span::def_id::DefId; +use std::collections::HashSet; use std::rc::Rc; fn is_cpp_movable<'tcx>(db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>) -> bool { @@ -1142,6 +1148,155 @@ impl<'tcx> TemplateSpecializationExt<'tcx> for RsStdEnumTemplateSpecialization<' } } +/// Collect trait implementations and map them to `TemplateSpecialization::TraitImpl`. +pub(crate) fn collect_trait_impls<'a, 'tcx>( + db: &'a BindingsGenerator<'tcx>, +) -> impl Iterator> + use<'a, 'tcx> { + let tcx = db.tcx(); + let supported_traits: Vec = db.supported_traits().iter().copied().collect(); + // TyCtxt makes it easy to get all the implementations of a trait, but there isn't an easy way + // to say give me all the trait implementations for this type. This is by design. The compiler + // lazily determines conformance to traits as needed for types and never computes every trait + // for a type in a single data structure. + // + // We, however, want every implementation for a supported type, so we can emit bindings to them. + // We achieve this by walking every supported trait, walking every implementation of that trait, + // and paring down to the implementations that receive bindings. + // + // A serendipitous side effect of this approach is that our implementations are emitted as a + // single list containing just implementations. We want to emit all of our implementations in a + // separate portion of our header from the rest of our bindings. Our impls become template + // specializaitons, which are required to be in an enclosing namespace of the template they + // specialize. This prevents them from living in the same namespace as our other bindings, as + // they may implement a trait that is not enclosed by that namespace. + supported_traits.into_iter().flat_map(move |trait_def_id| { + use rustc_middle::ty::fast_reject::SimplifiedType; + tcx.trait_impls_of(trait_def_id) + .non_blanket_impls() + .into_iter() + .filter_map(move |(simple_ty, impl_def_ids)| match simple_ty { + SimplifiedType::Adt(did) => { + // Only bind implementations for supported ADTs. + let canonical_name = db.symbol_canonical_name(*did)?; + // We explicitly want to allow ADTs that specify cpp_type. + // These are typically C++ types that have generated Rust bindings. + if canonical_name.unqualified.cpp_type.is_none() + && db.adt_needs_bindings(*did).is_err() + { + return None; + } + let crate_name = tcx.crate_name(did.krate); + // TODO: b/391443811 - Add support for implementations of stdlib types once + // we have headers that can be included for those types. + if ["std", "core", "alloc"].contains(&crate_name.as_str()) { + return None; + } + let adt_cc_name = canonical_name.format_for_cc(db).ok()?; + Some((adt_cc_name, impl_def_ids)) + } + // TODO: b/457803426 - Support trait implementations for non-adt types. + _ => None, + }) + .flat_map(move |(adt_cc_name, impl_def_ids)| { + impl_def_ids + .iter() + .copied() + // TODO: b/458768435 - This is technically suboptimal. We could instead only + // query for the impls from this crate, but the logic is complicated by + // supporting LOCAL_CRATE. Revisit once we've migrated to rmetas. + .filter(|impl_def_id| impl_def_id.krate == db.source_crate_num()) + .map(move |impl_def_id| { + TemplateSpecialization::TraitImpl(TraitImplTemplateSpecialization { + self_ty_cc_name: adt_cc_name.clone(), + trait_impl: impl_def_id, + }) + }) + }) + }) +} + +fn generate_trait_impl_specialization<'tcx>( + db: &BindingsGenerator<'tcx>, + trait_impl: &TraitImplTemplateSpecialization, +) -> std::result::Result, (DefId, Error)> { + let tcx = db.tcx(); + let impl_def_id = trait_impl.trait_impl; + let trait_header = tcx.impl_trait_header(impl_def_id); + #[rustversion::before(2025-10-17)] + let trait_header = trait_header.expect("Trait impl should have a trait header"); + let trait_ref = trait_header.trait_ref.instantiate_identity(); + let trait_def_id = trait_ref.def_id; + + let canonical_trait_name = db.symbol_canonical_name(trait_def_id).expect( + "symbol_canonical_name was unexpectedly called on a trait without a canonical name", + ); + let trait_name = canonical_trait_name.format_for_cc(db).map_err(|err| (impl_def_id, err))?; + + let mut prereqs = CcPrerequisites::default(); + let trait_args: Vec<_> = trait_ref + .args + .iter() + // Skip self type. + .skip(1) + .filter_map(|arg| arg.as_type()) + .map(|arg| { + if arg.flags().contains(has_type_or_const_vars()) { + return Err((impl_def_id, anyhow!("Implementation of traits must specify all types to receive bindings."))); + } + if arg.walk().any(|arg| arg.as_type().is_some_and(|ty| ty.is_ptr_sized_integral())) { + return Err(( + impl_def_id, + anyhow!( + "b/491106325 - isize and usize types are not yet supported as trait type arguments." + ), + )); + } + db.format_ty_for_cc(arg, TypeLocation::Other) + .map(|snippet| snippet.into_tokens(&mut prereqs)) + .map_err(|err| (impl_def_id, err)) + }) + .collect::, _>>()?; + + let type_args = if trait_args.is_empty() { + quote! {} + } else { + quote! { <#(#trait_args),*> } + }; + + let trait_name_with_args = quote! { #trait_name #type_args }; + + prereqs.depend_on_def(db, trait_def_id).map_err(|err| (impl_def_id, err))?; + + let mut member_function_names = HashSet::new(); + let assoc_items: ApiSnippets = tcx + .associated_items(impl_def_id) + .in_definition_order() + .flat_map(|assoc_item| generate_associated_item(db, assoc_item, &mut member_function_names)) + .collect(); + + let main_api = assoc_items.main_api.into_tokens(&mut prereqs); + prereqs.includes.insert(db.support_header("rs_std/traits.h")); + + let self_ty_cc_name = &trait_impl.self_ty_cc_name; + Ok(ApiSnippets { + main_api: CcSnippet { + tokens: quote! { + __NEWLINE__ + template<> + struct rs_std::impl<#self_ty_cc_name, #trait_name_with_args> { + static constexpr bool kIsImplemented = true; + + #main_api + }; + __NEWLINE__ + }, + prereqs, + }, + cc_details: assoc_items.cc_details, + rs_details: assoc_items.rs_details, + }) +} + /// Generate a template specialization. pub fn generate_template_specialization<'tcx>( db: &BindingsGenerator<'tcx>, @@ -1149,6 +1304,11 @@ pub fn generate_template_specialization<'tcx>( ) -> ApiSnippets<'tcx> { let mut snippets = match &specialization { TemplateSpecialization::RsStdEnum(rs_std_enum) => rs_std_enum.clone().api_snippets(db), + TemplateSpecialization::TraitImpl(trait_impl) => { + generate_trait_impl_specialization(db, trait_impl).unwrap_or_else(|(def_id, err)| { + generate_unsupported_def(db, def_id, err).into_main_api() + }) + } }; // Because we reuse logic from generate_struct_and_union here, we will add our `self_ty` as a template specialization of it's own specialization creating a depedency cycle. // We break that loop manually here to avoid that. diff --git a/cc_bindings_from_rs/generate_bindings/lib.rs b/cc_bindings_from_rs/generate_bindings/lib.rs index 0b80a4cca..7fcdce3df 100644 --- a/cc_bindings_from_rs/generate_bindings/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/lib.rs @@ -34,13 +34,13 @@ use crate::generate_function::{generate_function, must_use_attr_of}; use crate::generate_function_thunk::{generate_trait_thunks, TraitThunks}; use crate::generate_struct_and_union::{ adt_needs_bindings, cpp_enum_cpp_underlying_type, from_trait_impls_by_argument, generate_adt, - generate_adt_core, generate_associated_item, has_type_or_const_vars, scalar_value_to_string, + generate_adt_core, scalar_value_to_string, }; +use crate::generate_template_specialization::collect_trait_impls; use arc_anyhow::{Context, Error, Result}; use code_gen_utils::{format_cc_includes, CcConstQualifier, CcInclude, NamespaceQualifier}; use database::code_snippet::{ - ApiSnippets, CcPrerequisites, CcSnippet, ExternCDecl, RsSnippet, - RsStdEnumTemplateSpecialization, RsStdEnumTemplateSpecializationCore, TemplateSpecialization, + ApiSnippets, CcPrerequisites, CcSnippet, ExternCDecl, RsSnippet, TemplateSpecialization, }; use database::{ AdtCoreBindings, ExportedPath, FineGrainedFeature, FullyQualifiedName, NoMoveOrAssign, @@ -1707,152 +1707,62 @@ struct FormattedItem<'tcx> { aliases: Vec, } -/// Generate bindings to supported trait implementations. An implementation is supported if both -/// its trait and implementing type receive bindings. -fn generate_trait_impls<'a, 'tcx>( - db: &'a BindingsGenerator<'tcx>, -) -> impl Iterator> + use<'a, 'tcx> { - let tcx = db.tcx(); - let supported_traits: Vec = db.supported_traits().iter().copied().collect(); - // TyCtxt makes it easy to get all the implementations of a trait, but there isn't an easy way - // to say give me all the trait implementations for this type. This is by design. The compiler - // lazily determines conformance to traits as needed for types and never computes every trait - // for a type in a single data structure. - // - // We, however, want every implementation for a supported type, so we can emit bindings to them. - // We achieve this by walking every supported trait, walking every implementation of that trait, - // and paring down to the implementations that receive bindings. - // - // A serendipitous side effect of this approach is that our implementations are emitted as a - // single list containing just implementations. We want to emit all of our implementations in a - // separate portion of our header from the rest of our bindings. Our impls become template - // specializaitons, which are required to be in an enclosing namespace of the template they - // specialize. This prevents them from living in the same namespace as our other bindings, as - // they may implement a trait that is not enclosed by that namespace. - supported_traits - .into_iter() - .flat_map(move |trait_def_id| { - use rustc_middle::ty::fast_reject::SimplifiedType; - tcx.trait_impls_of(trait_def_id) - .non_blanket_impls() - .into_iter() - .filter_map(move |(simple_ty, impl_def_ids)| match simple_ty { - SimplifiedType::Adt(did) => { - // Only bind implementations for supported ADTs. - let canonical_name = db.symbol_canonical_name(*did)?; - // We explicitly want to allow ADTs that specify cpp_type. - // These are typically C++ types that have generated Rust bindings. - if canonical_name.unqualified.cpp_type.is_none() - && db.adt_needs_bindings(*did).is_err() { - return None; - } - let crate_name = tcx.crate_name(did.krate); - // TODO: b/391443811 - Add support for implementations of stdlib types once - // we have headers that can be included for those types. - if ["std", "core", "alloc"].contains(&crate_name.as_str()) { - return None; - } - let adt_cc_name = canonical_name.format_for_cc(db).ok()?; - Some((adt_cc_name, trait_def_id, impl_def_ids)) - } - // TODO: b/457803426 - Support trait implementations for non-adt types. - _ => None, - }) - .flat_map(move |(adt_cc_name, trait_def_id, impl_def_ids)| { - impl_def_ids - .iter() - .copied() - // TODO: b/458768435 - This is technically suboptimal. We could instead only - // query for the impls from this crate, but the logic is complicated by - // supporting LOCAL_CRATE. Revisit once we've migrated to rmetas. - .filter(|impl_def_id| impl_def_id.krate == db.source_crate_num()) - .map(move |impl_def_id| (adt_cc_name.clone(), trait_def_id, impl_def_id)) - }) - }) - .map( - move |(adt_cc_name, trait_def_id, impl_def_id)| -> Result { - let trait_header = tcx.impl_trait_header(impl_def_id); - #[rustversion::before(2025-10-17)] - let trait_header = trait_header.expect("Trait impl should have a trait header"); - let trait_ref = trait_header.trait_ref.instantiate_identity(); - - let canonical_name = db.symbol_canonical_name(trait_def_id).expect( - "symbol_canonical_name was unexpectedly called on a trait without a canonical name", - ); - let trait_name = - canonical_name.format_for_cc(db).map_err(|err| (impl_def_id, err))?; +struct GeneratedSpecializations<'tcx> { + specializations: HashMap, CcSnippet<'tcx>>, + impls_cc_details: Vec, +} - let mut prereqs = CcPrerequisites::default(); - let trait_args: Vec<_> = trait_ref - .args - .iter() - // Skip self type. - .skip(1) - .filter_map(|arg| arg.as_type()) - .map(|arg| { - if arg.flags().contains(has_type_or_const_vars()) { - return Err((impl_def_id, anyhow!("Implementation of traits must specify all types to receive bindings."))); - } - if arg.walk().any(|arg| arg.as_type().is_some_and(|ty| ty.is_ptr_sized_integral())) { - return Err(( - impl_def_id, - anyhow!( - "b/491106325 - isize and usize types are not yet supported as trait type arguments." - ), - )); - } - db.format_ty_for_cc(arg, TypeLocation::Other) - .map(|snippet| snippet.into_tokens(&mut prereqs)) - .map_err(|err| (impl_def_id, err)) - }) - .collect::, _>>()?; +/// Generates template specializations for a given worklist, and transitively discovers +/// any specializations required by the generated specializations. +fn generate_specializations_fixpoint<'tcx>( + db: &BindingsGenerator<'tcx>, + mut worklist: Vec>, + cc_details_prereqs: &mut CcPrerequisites<'tcx>, + extern_c_decls: &mut BTreeSet, + cc_api_impl: &mut TokenStream, +) -> GeneratedSpecializations<'tcx> { + let mut seen = HashSet::new(); + let mut specializations = HashMap::new(); + let mut impls_cc_details = Vec::new(); + + while !worklist.is_empty() { + // Sort to ensure deterministic processing. + worklist.sort_unstable_by(|a, b| template_specialization_cmp(db.tcx(), a, b)); + + let mut next_worklist = Vec::new(); + for spec in worklist { + if seen.contains(&spec) { + continue; + } - let type_args = if trait_args.is_empty() { - quote! {} - } else { - quote! { <#(#trait_args),*> } - }; + let snippets = generate_template_specialization::generate_template_specialization( + db, + spec.clone(), + ); + seen.insert(spec.clone()); - let trait_name_with_args = quote! { #trait_name #type_args }; + // Collect specializations required by the main_api. + for new_spec in snippets.main_api.prereqs.template_specializations.iter() { + if !seen.contains(new_spec) { + next_worklist.push(new_spec.clone()); + } + } - prereqs.depend_on_def(db, trait_def_id).map_err(|err| (impl_def_id, err))?; + impls_cc_details.push(snippets.cc_details.into_tokens(cc_details_prereqs)); + // Collect any transitive specializations discovered in cc_details. + for new_spec in std::mem::take(&mut cc_details_prereqs.template_specializations) { + if !seen.contains(&new_spec) { + next_worklist.push(new_spec); + } + } - let mut member_function_names = HashSet::new(); - let assoc_items: ApiSnippets = tcx - .associated_items(impl_def_id) - .in_definition_order() - .flat_map(|assoc_item| { - generate_associated_item(db, assoc_item, &mut member_function_names) - }) - .collect(); - - let main_api = assoc_items.main_api.into_tokens(&mut prereqs); - prereqs.includes.insert(db.support_header("rs_std/traits.h")); - - Ok(ApiSnippets { - main_api: CcSnippet { - tokens: quote! { - __NEWLINE__ - template<> - struct rs_std::impl<#adt_cc_name, #trait_name_with_args> { - static constexpr bool kIsImplemented = true; - - #main_api - }; - __NEWLINE__ - }, - prereqs, - }, - cc_details: assoc_items.cc_details, - rs_details: assoc_items.rs_details, - }) - }, - ) - .map(|results_snippets| { - results_snippets.unwrap_or_else(|(def_id, err)| { - generate_unsupported_def(db, def_id, err).into_main_api() - }) - }) + cc_api_impl.extend(snippets.rs_details.into_tokens(extern_c_decls)); + specializations.insert(spec, snippets.main_api); + } + worklist = next_worklist; + } + + GeneratedSpecializations { specializations, impls_cc_details } } fn formatted_items_in_crate<'tcx>( @@ -1894,16 +1804,14 @@ fn template_specialization_cmp<'tcx>( right: &TemplateSpecialization<'tcx>, ) -> std::cmp::Ordering { match (left, right) { - ( - TemplateSpecialization::RsStdEnum(RsStdEnumTemplateSpecialization { - core: RsStdEnumTemplateSpecializationCore { self_ty_rs: left_ty, .. }, - .. - }), - TemplateSpecialization::RsStdEnum(RsStdEnumTemplateSpecialization { - core: RsStdEnumTemplateSpecializationCore { self_ty_rs: right_ty, .. }, - .. - }), - ) => left_ty.sort_string(tcx).cmp(&right_ty.sort_string(tcx)), + (TemplateSpecialization::RsStdEnum(left), TemplateSpecialization::RsStdEnum(right)) => { + left.core.self_ty_rs.sort_string(tcx).cmp(&right.core.self_ty_rs.sort_string(tcx)) + } + (TemplateSpecialization::TraitImpl(left), TemplateSpecialization::TraitImpl(right)) => { + stable_def_id_cmp(tcx, left.trait_impl, right.trait_impl) + } + (TemplateSpecialization::RsStdEnum(_), _) => Ordering::Less, + (_, TemplateSpecialization::RsStdEnum(_)) => Ordering::Greater, } } @@ -1962,48 +1870,23 @@ fn generate_crate(db: &BindingsGenerator) -> Result { cc_api_impl.extend(api_snippets.rs_details.into_tokens(&mut extern_c_decls)); } - // Because trait implementations are template specialization, they can't live in the top-level - // namespace generated for our other definitions. Template specializations must live in an - // enclosing namespace of the template they specialize. For this reason, we put our specializations in the top level namespace. The remainder of our implementation code, should be handled like normal. - // We append our cc_details and rs_details here, so that they get processed like normal, but save our main_api to be specially placed in the top level namespace. - let mut impls_cc_details = vec![]; - let impls = generate_trait_impls(db) - .map(|snippets| { - impls_cc_details.push(snippets.cc_details.clone().into_tokens(&mut cc_details_prereqs)); - cc_api_impl.extend(snippets.rs_details.clone().into_tokens(&mut extern_c_decls)); - snippets.main_api.clone().into_tokens(&mut cc_details_prereqs) - }) - .collect::>(); - let impls_tokens = if impls.is_empty() { - // Exclude leading newline for an empty impls list. - quote! {} - } else { - quote! { - __NEWLINE__ - #(#impls)__NEWLINE__* - } - }; - - let mut specializations = std::mem::take(&mut cc_details_prereqs.template_specializations); - specializations.extend( - main_apis.values().flat_map(|api| api.prereqs.template_specializations.iter()).cloned(), - ); - - let mut specializations: HashMap = specializations + let worklist: Vec<_> = std::mem::take(&mut cc_details_prereqs.template_specializations) .into_iter() - // We sort here, so our details are added in a consistent order. - .sorted_unstable_by(|a, b| template_specialization_cmp(db.tcx(), a, b)) - .map(|spec| { - let snippets = generate_template_specialization::generate_template_specialization( - db, - spec.clone(), - ); - impls_cc_details.push(snippets.cc_details.clone().into_tokens(&mut cc_details_prereqs)); - cc_api_impl.extend(snippets.rs_details.clone().into_tokens(&mut extern_c_decls)); - (spec, snippets.main_api) - }) + .chain( + main_apis.values().flat_map(|api| api.prereqs.template_specializations.iter()).cloned(), + ) + .chain(collect_trait_impls(db)) .collect(); + let GeneratedSpecializations { mut specializations, impls_cc_details } = + generate_specializations_fixpoint( + db, + worklist, + &mut cc_details_prereqs, + &mut extern_c_decls, + &mut cc_api_impl, + ); + // Find the order of `main_apis` that 1) meets the requirements of // `CcPrerequisites::defs` and 2) makes a best effort attempt to keep the // `main_apis` in the same order as the source order of the Rust APIs. @@ -2044,6 +1927,7 @@ fn generate_crate(db: &BindingsGenerator) -> Result { .template_specializations .iter() .cloned() + //.filter(|spec| specializations.contains_key(spec)) .map(Node::Specialization), ); predecessors.map(move |predecessor| toposort::Dependency { @@ -2162,7 +2046,6 @@ fn generate_crate(db: &BindingsGenerator) -> Result { __NEWLINE__ __NEWLINE__ #ordered_cc __NEWLINE__ - #impls_tokens #(#impls_cc_details)__NEWLINE__* __NEWLINE__ } diff --git a/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h b/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h index 7f3de953b..4c73899ec 100644 --- a/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h +++ b/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h @@ -41,6 +41,8 @@ struct rs_std::impl { static std::int32_t get_value(CcType const& self); }; +namespace trait {} + namespace trait { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_Trait_uget_uvalue(CcType const&); diff --git a/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h b/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h index 84a1e1542..cade5e1a2 100644 --- a/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h +++ b/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h @@ -118,6 +118,38 @@ struct CRUBIT_INTERNAL_RUST_TYPE( using impl = rs_std::impl>; }; +} // namespace generic_traits + +// Error generating bindings for `>` defined at +// cc_bindings_from_rs/test/traits/generic_traits.rs;l=42: +// The following Rust type is not supported yet: U + +template <> +struct rs_std::impl<::generic_traits::StructGeneric, + ::generic_traits::TraitWithGeneric> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/generic_traits.rs;l=21 + static std::int32_t foo(::generic_traits::StructGeneric const& self, + std::int32_t t); +}; + +template <> +struct rs_std::impl< + ::generic_traits::StructGeneric, + ::generic_traits::TraitWithTwoGenerics> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/generic_traits.rs;l=32 + static std::int32_t bar(::generic_traits::StructGeneric const& self, + std::int32_t t, std::int32_t u); +}; + +namespace generic_traits { + static_assert( sizeof(AnotherStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -158,34 +190,6 @@ inline void StructGeneric::__crubit_field_offset_assertions() { } } // namespace generic_traits -template <> -struct rs_std::impl<::generic_traits::StructGeneric, - ::generic_traits::TraitWithGeneric> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/generic_traits.rs;l=21 - static std::int32_t foo(::generic_traits::StructGeneric const& self, - std::int32_t t); -}; - -template <> -struct rs_std::impl< - ::generic_traits::StructGeneric, - ::generic_traits::TraitWithTwoGenerics> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/generic_traits.rs;l=32 - static std::int32_t bar(::generic_traits::StructGeneric const& self, - std::int32_t t, std::int32_t u); -}; - -// Error generating bindings for `>` defined at -// cc_bindings_from_rs/test/traits/generic_traits.rs;l=42: -// The following Rust type is not supported yet: U - namespace generic_traits { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_TraitWithGeneric_ufoo( diff --git a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h index afc3565e1..2758899a9 100644 --- a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h +++ b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h @@ -65,6 +65,19 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: trait_definition_golden :: MyTrait") using impl = rs_std::impl; }; +} // namespace trait_definition + +template <> +struct rs_std::impl<::trait_definition::MyStruct, ::trait_definition::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition.rs;l=14 + static std::int32_t do_something(::trait_definition::MyStruct const& self); +}; + +namespace trait_definition { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -81,15 +94,6 @@ inline void MyStruct::__crubit_field_offset_assertions() { } } // namespace trait_definition -template <> -struct rs_std::impl<::trait_definition::MyStruct, ::trait_definition::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition.rs;l=14 - static std::int32_t do_something(::trait_definition::MyStruct const& self); -}; - namespace trait_definition { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_udo_usomething( diff --git a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h index b77fe8238..f38e6ffc0 100644 --- a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h +++ b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h @@ -97,6 +97,19 @@ NotImplemented final { static void __crubit_field_offset_assertions(); }; +} // namespace trait_impl + +template <> +struct rs_std::impl<::trait_impl::MyStruct, ::trait_definition::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl.rs;l=18 + static std::int32_t do_something(::trait_impl::MyStruct const& self); +}; + +namespace trait_impl { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -136,15 +149,6 @@ inline void NotImplemented::__crubit_field_offset_assertions() { } } // namespace trait_impl -template <> -struct rs_std::impl<::trait_impl::MyStruct, ::trait_definition::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl.rs;l=18 - static std::int32_t do_something(::trait_impl::MyStruct const& self); -}; - namespace trait_impl { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_udo_usomething( diff --git a/cc_bindings_from_rs/test/traits/traits_cc_api.h b/cc_bindings_from_rs/test/traits/traits_cc_api.h index 5ff4d95e5..2830f2949 100644 --- a/cc_bindings_from_rs/test/traits/traits_cc_api.h +++ b/cc_bindings_from_rs/test/traits/traits_cc_api.h @@ -282,6 +282,129 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: traits_golden :: TraitWithAssociatedConst") using impl = rs_std::impl; }; +} // namespace traits + +template <> +struct rs_std::impl<::traits::AssociatedTypeStruct, + ::traits::AssociatedTypeTrait> { + static constexpr bool kIsImplemented = true; + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=148 + using MyAssocType CRUBIT_INTERNAL_RUST_TYPE( + "::MyAssocType") = std::int32_t; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=149 + static std::int32_t get_my_assoc_type( + ::traits::AssociatedTypeStruct const& self); + + // Error generating bindings for `::UnsupportedAssocType` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=154: + // Definition `std::string::String` comes from the `alloc` crate, but no + // `--crate-header` was specified for this crate + + // Error generating bindings for `::get_unsupported_assoc_type` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=155: + // Error formatting function return type `std::string::String`: Definition + // `std::string::String` comes from the `alloc` crate, but no `--crate-header` + // was specified for this crate +}; + +template <> +struct rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=95 + static std::int32_t const& $a + trait_do_something(::traits::LifetimeStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=99 + static std::int32_t const& $(__anon1) + function_do_something(::traits::LifetimeStruct const& self); +}; + +template <> +struct rs_std::impl<::traits::MyStruct, ::traits::DifferentTraitSameName> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=79 + static std::int32_t do_something(::traits::MyStruct const& self); +}; + +template <> +struct rs_std::impl<::traits::MyStruct, ::traits::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=57 + static std::int32_t do_something(::traits::MyStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=61 + static std::int32_t consume_self(::traits::MyStruct self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=65 + static ::traits::MyStruct const& $(__anon1) + return_self(::traits::MyStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=69 + static std::int32_t no_self(); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=73 + static std::tuple take_and_return_other_types( + ::traits::MyStruct const& self, ::traits::Foo x); +}; + +template <> +struct rs_std::impl<::traits::MyStruct2, ::traits::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=110 + static std::int32_t do_something(::traits::MyStruct2 const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=114 + static std::int32_t consume_self(::traits::MyStruct2 self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=118 + static ::traits::MyStruct2 const& $(__anon1) + return_self(::traits::MyStruct2 const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=122 + static std::int32_t no_self(); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=126 + static std::tuple take_and_return_other_types( + ::traits::MyStruct2 const& self, ::traits::Foo x); +}; + +template <> +struct rs_std::impl<::traits::StructWithAssociatedConst, + ::traits::TraitWithAssociatedConst> { + static constexpr bool kIsImplemented = true; + static constexpr std::int32_t CONST_INT = INT32_C(10); + + // Error generating bindings for `::CONST_STRUCT` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=174: + // Unsupported constant type: traits_golden::StructWithAssociatedConst +}; + +namespace traits { + static_assert( sizeof(AssociatedTypeStruct) == 32, "Verify that ADT layout didn't change since this header got generated"); @@ -450,124 +573,60 @@ inline void StructWithAssociatedConst::__crubit_field_offset_assertions() { } } // namespace traits -template <> -struct rs_std::impl<::traits::MyStruct, ::traits::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=57 - static std::int32_t do_something(::traits::MyStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=61 - static std::int32_t consume_self(::traits::MyStruct self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=65 - static ::traits::MyStruct const& $(__anon1) - return_self(::traits::MyStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=69 - static std::int32_t no_self(); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=73 - static std::tuple take_and_return_other_types( - ::traits::MyStruct const& self, ::traits::Foo x); -}; - -template <> -struct rs_std::impl<::traits::MyStruct2, ::traits::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=110 - static std::int32_t do_something(::traits::MyStruct2 const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=114 - static std::int32_t consume_self(::traits::MyStruct2 self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=118 - static ::traits::MyStruct2 const& $(__anon1) - return_self(::traits::MyStruct2 const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=122 - static std::int32_t no_self(); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=126 - static std::tuple take_and_return_other_types( - ::traits::MyStruct2 const& self, ::traits::Foo x); -}; - -template <> -struct rs_std::impl<::traits::MyStruct, ::traits::DifferentTraitSameName> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=79 - static std::int32_t do_something(::traits::MyStruct const& self); -}; - -template <> -struct rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=95 - static std::int32_t const& $a - trait_do_something(::traits::LifetimeStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=99 - static std::int32_t const& $(__anon1) - function_do_something(::traits::LifetimeStruct const& self); -}; - -template <> -struct rs_std::impl<::traits::AssociatedTypeStruct, - ::traits::AssociatedTypeTrait> { - static constexpr bool kIsImplemented = true; - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=148 - using MyAssocType CRUBIT_INTERNAL_RUST_TYPE( - "::MyAssocType") = std::int32_t; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=149 - static std::int32_t get_my_assoc_type( - ::traits::AssociatedTypeStruct const& self); - - // Error generating bindings for `::UnsupportedAssocType` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=154: - // Definition `std::string::String` comes from the `alloc` crate, but no - // `--crate-header` was specified for this crate +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t +__crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( + ::traits::AssociatedTypeStruct const&); +} +} // namespace traits +inline std::int32_t +rs_std::impl<::traits::AssociatedTypeStruct, ::traits::AssociatedTypeTrait>:: + get_my_assoc_type(::traits::AssociatedTypeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype(self); +} - // Error generating bindings for `::get_unsupported_assoc_type` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=155: - // Error formatting function return type `std::string::String`: Definition - // `std::string::String` comes from the `alloc` crate, but no `--crate-header` - // was specified for this crate -}; +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t const& $a +__crubit_thunk_LifetimeTrait_utrait_udo_usomething( + ::traits::LifetimeStruct const&); +} +} // namespace traits +inline std::int32_t const& $a +rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: + trait_do_something(::traits::LifetimeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_LifetimeTrait_utrait_udo_usomething(self); +} -template <> -struct rs_std::impl<::traits::StructWithAssociatedConst, - ::traits::TraitWithAssociatedConst> { - static constexpr bool kIsImplemented = true; - static constexpr std::int32_t CONST_INT = INT32_C(10); +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t const& $(__anon1) + __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( + ::traits::LifetimeStruct const&); +} +} // namespace traits +inline std::int32_t const& $( + __anon1) rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: + function_do_something(::traits::LifetimeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_LifetimeTrait_ufunction_udo_usomething(self); +} - // Error generating bindings for `::CONST_STRUCT` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=174: - // Unsupported constant type: traits_golden::StructWithAssociatedConst -}; +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t __crubit_thunk_DifferentTraitSameName_udo_usomething( + ::traits::MyStruct const&); +} +} // namespace traits +inline std::int32_t rs_std:: + impl<::traits::MyStruct, ::traits::DifferentTraitSameName>::do_something( + ::traits::MyStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_DifferentTraitSameName_udo_usomething(self); +} namespace traits { namespace __crubit_internal { @@ -705,60 +764,5 @@ inline std::tuple rs_std:: return std::make_tuple(*__return_value_0_storage, *__return_value_1_storage); } -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t __crubit_thunk_DifferentTraitSameName_udo_usomething( - ::traits::MyStruct const&); -} -} // namespace traits -inline std::int32_t rs_std:: - impl<::traits::MyStruct, ::traits::DifferentTraitSameName>::do_something( - ::traits::MyStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_DifferentTraitSameName_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t const& $a -__crubit_thunk_LifetimeTrait_utrait_udo_usomething( - ::traits::LifetimeStruct const&); -} -} // namespace traits -inline std::int32_t const& $a -rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: - trait_do_something(::traits::LifetimeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_LifetimeTrait_utrait_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t const& $(__anon1) - __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( - ::traits::LifetimeStruct const&); -} -} // namespace traits -inline std::int32_t const& $( - __anon1) rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: - function_do_something(::traits::LifetimeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_LifetimeTrait_ufunction_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t -__crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( - ::traits::AssociatedTypeStruct const&); -} -} // namespace traits -inline std::int32_t -rs_std::impl<::traits::AssociatedTypeStruct, ::traits::AssociatedTypeTrait>:: - get_my_assoc_type(::traits::AssociatedTypeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype(self); -} - #pragma clang diagnostic pop #endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_TRAITS_TRAITS_GOLDEN diff --git a/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs b/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs index aebe846e9..e130337de 100644 --- a/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs @@ -103,6 +103,42 @@ unsafe extern "C" fn __crubit_thunk_default(__ret_ptr: *mut core::ffi::c_void) - } const _: () = assert!(::core::mem::offset_of!(::traits_golden::StructWithAssociatedConst, x) == 0); #[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( + __self: &'static ::traits_golden::AssociatedTypeStruct, +) -> i32 { + unsafe { + <::traits_golden::AssociatedTypeStruct as::traits_golden::AssociatedTypeTrait>::get_my_assoc_type(__self) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_LifetimeTrait_utrait_udo_usomething( + __self: &'static ::traits_golden::LifetimeStruct<'static>, +) -> &'static i32 { + unsafe { + <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::trait_do_something( + __self, + ) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( + __self: &'static ::traits_golden::LifetimeStruct<'static>, +) -> &'static i32 { + unsafe { + <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::function_do_something( + __self, + ) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_DifferentTraitSameName_udo_usomething( + __self: &'static ::traits_golden::MyStruct, +) -> i32 { + unsafe { + <::traits_golden::MyStruct as ::traits_golden::DifferentTraitSameName>::do_something(__self) + } +} +#[unsafe(no_mangle)] unsafe extern "C" fn __crubit_thunk_MyTrait_udo_usomething( __self: &'static ::traits_golden::MyStruct, ) -> i32 { @@ -188,39 +224,3 @@ unsafe extern "C" fn __crubit_thunk_MyTrait_utake_uand_ureturn_uother_utypes( (__ret_ptr_1 as *mut i32).write(__rs_return_value_1); } } -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_DifferentTraitSameName_udo_usomething( - __self: &'static ::traits_golden::MyStruct, -) -> i32 { - unsafe { - <::traits_golden::MyStruct as ::traits_golden::DifferentTraitSameName>::do_something(__self) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_LifetimeTrait_utrait_udo_usomething( - __self: &'static ::traits_golden::LifetimeStruct<'static>, -) -> &'static i32 { - unsafe { - <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::trait_do_something( - __self, - ) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( - __self: &'static ::traits_golden::LifetimeStruct<'static>, -) -> &'static i32 { - unsafe { - <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::function_do_something( - __self, - ) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( - __self: &'static ::traits_golden::AssociatedTypeStruct, -) -> i32 { - unsafe { - <::traits_golden::AssociatedTypeStruct as::traits_golden::AssociatedTypeTrait>::get_my_assoc_type(__self) - } -} diff --git a/examples/rust/trait/example_generated.h b/examples/rust/trait/example_generated.h index c955a7de1..1a3e08aae 100644 --- a/examples/rust/trait/example_generated.h +++ b/examples/rust/trait/example_generated.h @@ -69,6 +69,24 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: example_crate_golden :: MyTrait") MyTrait { using impl = rs_std::impl; }; +} // namespace example_crate + +template <> +struct rs_std::impl<::example_crate::MyStruct, ::example_crate::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // examples/rust/trait/example.rs;l=23 + static std::int32_t add_with(::example_crate::MyStruct const& self, + std::int32_t y); + + // Generated from: + // examples/rust/trait/example.rs;l=27 + static rs_std::StrRef describe(::example_crate::MyStruct const& self); +}; + +namespace example_crate { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -103,20 +121,6 @@ inline void MyStruct::__crubit_field_offset_assertions() { } } // namespace example_crate -template <> -struct rs_std::impl<::example_crate::MyStruct, ::example_crate::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // examples/rust/trait/example.rs;l=23 - static std::int32_t add_with(::example_crate::MyStruct const& self, - std::int32_t y); - - // Generated from: - // examples/rust/trait/example.rs;l=27 - static rs_std::StrRef describe(::example_crate::MyStruct const& self); -}; - namespace example_crate { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_uadd_uwith(