diff --git a/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl index adf4c3af0..c30f4bfec 100644 --- a/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl +++ b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl @@ -558,6 +558,7 @@ private_common_attrs = { "//support/public:result", "//support/public:tuple", "//support/public:vec", + "//support/public:iterator_adapter", ], ), "_process_wrapper": attr.label( 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 6ad4aa3e7..8d1932c50 100644 --- a/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs +++ b/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs @@ -277,6 +277,10 @@ impl<'tcx> CcPrerequisites<'tcx> { .extend(std::mem::take(&mut self.template_specializations)); } + pub fn move_only_defs_to_fwd_decls(&mut self) { + self.fwd_decls.extend(std::mem::take(&mut self.defs)); + } + /// Move any definitions that appear in `ty` to the forward declarations of `prereqs`. pub fn forward_declare_type(&mut self, ty: Ty<'tcx>) { let mut adts = HashSet::new(); diff --git a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs index 8390fff2b..349d85df6 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs @@ -28,7 +28,10 @@ use arc_anyhow::{Context, Result}; use code_gen_utils::{ escape_non_identifier_chars, expect_format_cc_type_name, make_rs_ident, CcInclude, }; -use database::code_snippet::{ApiSnippets, CcPrerequisites, CcSnippet}; +use database::code_snippet::{ + ApiSnippets, CcPrerequisites, CcSnippet, TemplateSpecialization, + TraitImplTemplateSpecialization, +}; use database::{AdtCoreBindings, BindingsGenerator, StaticMethodMode, TypeLocation}; use error_report::{anyhow, bail, ensure}; use itertools::Itertools; @@ -1180,6 +1183,8 @@ pub fn generate_adt<'tcx>( let trait_operator_snippets = generate_trait_operator_impls(db, core.as_ref()); let constructor_operator_snippets = generate_constructor_impls(db, core.as_ref()); let display_snippets = generate_display_impl(db, core.as_ref()); + let into_iterator_snippets = + generate_into_iterator_impls(db, core.as_ref(), &mut member_function_names); let ApiSnippets { main_api: public_functions_main_api, @@ -1197,6 +1202,7 @@ pub fn generate_adt<'tcx>( trait_operator_snippets, constructor_operator_snippets, display_snippets, + into_iterator_snippets, ] .into_iter() .collect(); @@ -2548,3 +2554,267 @@ pub(crate) fn generate_relocating_ctor<'tcx>( main_api.prereqs.includes.insert(CcInclude::cstring()); main_api.into_main_api() } + +#[derive(Clone, Copy, PartialEq, Eq)] +enum PassingMode { + Value, + SharedRef, + MutRef, +} + +fn get_into_iter_ty<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + into_iterator_trait_id: DefId, +) -> Result> { + let into_iter_assoc_item = tcx + .associated_items(into_iterator_trait_id) + .in_definition_order() + .find(|item| { + item.name() == rustc_span::symbol::Symbol::intern("IntoIter") + && matches!(item.kind, ty::AssocKind::Type { .. }) + }) + .expect("IntoIter to be a required associated item of IntoIterator"); + + let projection_ty = Ty::new_projection(tcx, into_iter_assoc_item.def_id, [self_ty]); + + query_compiler::try_normalize( + tcx, + ty::PseudoCanonicalInput { + typing_env: rustc_middle::ty::TypingEnv::fully_monomorphized(), + value: projection_ty, + }, + ) + .map_err(|_| anyhow!("Failed to normalize `<{} as IntoIterator>::IntoIter`", self_ty)) +} + +fn get_into_iter_item_ty<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + into_iterator_trait_id: DefId, +) -> Result> { + let item_assoc_item = tcx + .associated_items(into_iterator_trait_id) + .in_definition_order() + .find(|item| { + item.name() == rustc_span::symbol::Symbol::intern("Item") + && matches!(item.kind, ty::AssocKind::Type { .. }) + }) + .expect("Item to be a required associated item of IntoIterator"); + + let projection_ty = Ty::new_projection(tcx, item_assoc_item.def_id, [self_ty]); + + query_compiler::try_normalize( + tcx, + ty::PseudoCanonicalInput { + typing_env: rustc_middle::ty::TypingEnv::fully_monomorphized(), + value: projection_ty, + }, + ) + .map_err(|_| anyhow!("Failed to normalize `<{} as IntoIterator>::Item`", self_ty)) +} + +fn generate_begin_and_end_for_type<'tcx>( + db: &BindingsGenerator<'tcx>, + core: &AdtCoreBindings<'tcx>, + into_iterator_trait_id: DefId, + passing_mode: PassingMode, +) -> Result>> { + let tcx = db.tcx(); + let self_ty = core.self_ty; + + let check_ty = match passing_mode { + PassingMode::Value => self_ty, + PassingMode::SharedRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty), + PassingMode::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty), + }; + + if !does_type_implement_trait(tcx, check_ty, into_iterator_trait_id, []) { + return Ok(None); + } + if let Some(iterator_trait_id) = tcx.get_diagnostic_item(sym::Iterator) + && does_type_implement_trait(tcx, self_ty, iterator_trait_id, []) + { + return Ok(None); + } + + let into_iter_ty = get_into_iter_ty(tcx, check_ty, into_iterator_trait_id)?; + + let item_ty = get_into_iter_item_ty(tcx, check_ty, into_iterator_trait_id)?; + + let _ = db + .format_ty_for_cc(item_ty, TypeLocation::Other) + .context("Failed to format IntoIterator::Item")?; + + let into_iter_cc_ty = db + .format_ty_for_cc(into_iter_ty, TypeLocation::Other) + .context("Failed to format IntoIterator::IntoIter")?; + + let static_check_ty = replace_all_regions_with_static(tcx, check_ty); + let rs_fully_qualified_name = db.format_ty_for_rs(static_check_ty)?; + + let TraitThunks { method_name_to_cc_thunk_name, cc_thunk_decls, rs_thunk_impls } = + generate_trait_thunks( + db, + into_iterator_trait_id, + &[], + check_ty, + core.def_id, + rs_fully_qualified_name, + /*is_constructor=*/ false, + )?; + + let into_iter_thunk_name = method_name_to_cc_thunk_name + .get(&sym::into_iter) + .expect("IntoIterator trait missing into_iter method"); + + let into_iter_fn_assoc_item = tcx + .associated_items(into_iterator_trait_id) + .in_definition_order() + .find(|item| item.name() == sym::into_iter && matches!(item.kind, ty::AssocKind::Fn { .. })) + .expect("IntoIterator should have into_iter method"); + let into_iter_fn_id = into_iter_fn_assoc_item.def_id; + + let adt_cc_name = &core.cc_short_name; + let param_cc_type_tokens = match passing_mode { + PassingMode::Value => quote! { #adt_cc_name && }, + PassingMode::SharedRef => quote! { const #adt_cc_name & }, + PassingMode::MutRef => quote! { #adt_cc_name & }, + }; + + let param = Param { + cc_name: format_ident!("self_"), + cpp_type: CcParamTy { + snippet: CcSnippet::new(param_cc_type_tokens.clone()), + is_lifetime_bound: false, + }, + ty: check_ty, + }; + + let impl_body = generate_thunk_call( + db, + into_iter_fn_id, + into_iter_thunk_name.clone(), + into_iter_ty, + ThunkSelfParameter::new( + /*has_self=*/ false, /*by_copy=*/ false, /*is_trait_method=*/ false, + ), + &[param], + )?; + + let mut main_api_prereqs = CcPrerequisites::default(); + let into_iter_cc_ty_tokens_main = into_iter_cc_ty.clone().into_tokens(&mut main_api_prereqs); + main_api_prereqs.includes.insert(db.support_header("rs_std/iterator_adapter.h")); + + let iterator_trait_id = tcx + .get_diagnostic_item(sym::Iterator) + .ok_or_else(|| anyhow!("Iterator trait not found"))?; + let mut impls = tcx.non_blanket_impls_for_ty(iterator_trait_id, into_iter_ty); + let Some(trait_impl_def_id) = impls.next() else { + return Ok(None); + }; + let generics = tcx.generics_of(trait_impl_def_id); + let has_type_or_const_params = generics.own_params.iter().any(|param| { + matches!( + param.kind, + ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } + ) + }); + if has_type_or_const_params { + bail!("IntoIterator/Iterator impls with generic type or const parameters are not supported yet."); + } + let specialization = TemplateSpecialization::TraitImpl(TraitImplTemplateSpecialization { + self_ty_cc_name: into_iter_cc_ty_tokens_main.clone(), + trait_impl: trait_impl_def_id, + }); + main_api_prereqs.template_specializations.insert(specialization); + + let (ref_qualifiers, self_binding) = match passing_mode { + PassingMode::Value => { + (quote! { && }, quote! { #adt_cc_name&& self_ = ::std::move(*this); }) + } + PassingMode::SharedRef => { + (quote! { const & }, quote! { const #adt_cc_name& self_ = *this; }) + } + PassingMode::MutRef => (quote! { & }, quote! { #adt_cc_name& self_ = *this; }), + }; + + main_api_prereqs.move_only_defs_to_fwd_decls(); + let main_api = CcSnippet { + tokens: quote! { + rs::IteratorAdapter< #into_iter_cc_ty_tokens_main > begin() #ref_qualifiers; + rs::IteratorEnd end() #ref_qualifiers; + }, + prereqs: main_api_prereqs, + }; + + let mut cc_details_prereqs = CcPrerequisites::default(); + let into_iter_cc_ty_tokens_details = into_iter_cc_ty.into_tokens(&mut cc_details_prereqs); + cc_details_prereqs.includes.insert(db.support_header("rs_std/iterator_adapter.h")); + + let cc_thunk_decls_tokens = cc_thunk_decls.into_tokens(&mut cc_details_prereqs); + let impl_body_tokens = impl_body.into_tokens(&mut cc_details_prereqs); + cc_details_prereqs.move_defs_to_fwd_decls(); + + let call_expr = if matches!(into_iter_ty.kind(), ty::Ref(..)) { + quote! { &call_into_iter() } + } else { + quote! { call_into_iter() } + }; + + let cc_details = CcSnippet { + tokens: quote! { + #cc_thunk_decls_tokens + + inline rs::IteratorAdapter< #into_iter_cc_ty_tokens_details > #adt_cc_name :: begin () #ref_qualifiers { + #self_binding + auto call_into_iter = [&]() -> decltype(auto) { + #impl_body_tokens + }; + return rs::IteratorAdapter< #into_iter_cc_ty_tokens_details >(#call_expr); + } + inline rs::IteratorEnd #adt_cc_name :: end () #ref_qualifiers { + return rs::IteratorEnd(); + } + }, + prereqs: cc_details_prereqs, + }; + + Ok(Some(ApiSnippets { main_api, cc_details, rs_details: rs_thunk_impls })) +} + +fn generate_into_iterator_impls<'tcx>( + db: &BindingsGenerator<'tcx>, + core: &AdtCoreBindings<'tcx>, + member_function_names: &mut HashSet, +) -> ApiSnippets<'tcx> { + let tcx = db.tcx(); + let Some(into_iterator_trait_id) = tcx.get_diagnostic_item(sym::IntoIterator) else { + return ApiSnippets::default(); + }; + + if member_function_names.contains("begin") || member_function_names.contains("end") { + return ApiSnippets::default(); + } + + let mut snippets = Vec::new(); + + let mut try_generate = |passing_mode| -> Result>> { + generate_begin_and_end_for_type(db, core, into_iterator_trait_id, passing_mode) + }; + + for mode in [PassingMode::Value, PassingMode::SharedRef, PassingMode::MutRef] { + match try_generate(mode) { + Ok(Some(s)) => snippets.push(s), + Ok(None) => {} + Err(err) => { + if let Some(def_id) = core.def_id { + let main_api = generate_unsupported_def(db, def_id, err); + snippets.push(ApiSnippets { main_api, ..Default::default() }); + } + } + } + } + + snippets.into_iter().collect() +} 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 f63d84cf2..6be2c17b7 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs @@ -1929,7 +1929,15 @@ fn generate_trait_impl_specialization<'tcx>( prereqs.depend_on_def(db, trait_def_id).map_err(|err| (impl_def_id, err))?; if let Some(adt) = trait_ref.self_ty().ty_adt_def() { - prereqs.depend_on_def(db, adt.did()).map_err(|err| (impl_def_id, err))?; + let def_id = adt.did(); + let canonical_name = db.symbol_canonical_name(def_id).expect( + "Self type should have a canonical name if we are generating a specialization for it", + ); + if canonical_name.krate_num == db.source_crate_num() { + prereqs.fwd_decls.insert(def_id); + } else { + prereqs.depend_on_def(db, def_id).map_err(|err| (impl_def_id, err))?; + } } let mut member_function_names = HashSet::new(); diff --git a/cc_bindings_from_rs/generate_bindings/lib.rs b/cc_bindings_from_rs/generate_bindings/lib.rs index 50c427aa4..a5b14ade5 100644 --- a/cc_bindings_from_rs/generate_bindings/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/lib.rs @@ -1279,6 +1279,7 @@ pub(crate) fn create_type_alias_with_rs_type<'tcx>( let cc_bindings = db.format_ty_for_cc(alias_type, TypeLocation::Other)?; let mut main_api_prereqs = CcPrerequisites::default(); let actual_type_name = cc_bindings.into_tokens(&mut main_api_prereqs); + main_api_prereqs.move_defs_to_fwd_decls(); let alias_name = format_cc_ident(db, alias_name).context("Error formatting type alias name")?; @@ -2271,6 +2272,7 @@ fn generate_crate(db: &BindingsGenerator) -> Result { .map(|(spec, main_api)| (Node::Specialization(spec.clone()), main_api)), ) .flat_map(|(successor, main_api)| { + let successor_clone = successor.clone(); let predecessors = main_api .prereqs .defs @@ -2286,13 +2288,15 @@ fn generate_crate(db: &BindingsGenerator) -> Result { .iter() .cloned() .map(Node::Specialization), - ); + ) + .filter(move |pre| pre != &successor_clone); predecessors.map(move |predecessor| toposort::Dependency { predecessor, successor: successor.clone(), }) }) .collect::>(); + let spec_keys: HashMap<&TemplateSpecialization<'_>, NodeSortKey> = specializations.keys().map(|spec| (spec, NodeSortKey::new(tcx, spec))).collect(); diff --git a/cc_bindings_from_rs/test/known_traits/into_iterator/BUILD b/cc_bindings_from_rs/test/known_traits/into_iterator/BUILD new file mode 100644 index 000000000..a6300d6d2 --- /dev/null +++ b/cc_bindings_from_rs/test/known_traits/into_iterator/BUILD @@ -0,0 +1,54 @@ +# End-to-end tests of `cc_bindings_from_rs`, focusing on the `IntoIterator` trait + +load( + "@rules_rust//rust:defs.bzl", + "rust_library", +) +load( + "//cc_bindings_from_rs/bazel_support:cc_bindings_from_rust_rule.bzl", + "cc_bindings_from_rust", +) +load( + "//cc_bindings_from_rs/test/golden:golden_test.bzl", + "golden_test", +) +load("//common:crubit_wrapper_macros_oss.bzl", "crubit_cc_test") + +package(default_applicable_licenses = ["//:license"]) + +licenses(["notice"]) + +rust_library( + name = "into_iterator_rust", + testonly = 1, + srcs = ["into_iterator.rs"], + aspect_hints = [ + "//features:experimental", + ], + deps = [ + "//support:bridge_rust", + ], +) + +golden_test( + name = "into_iterator_golden_test", + basename = "into_iterator", + golden_h = "into_iterator_cc_api.h", + golden_rs = "into_iterator_cc_api_impl.rs", + rust_library = "into_iterator_rust", +) + +cc_bindings_from_rust( + name = "into_iterator_cc_api", + testonly = 1, + crate = ":into_iterator_rust", +) + +crubit_cc_test( + name = "into_iterator_cc_test", + srcs = ["into_iterator_test.cc"], + deps = [ + ":into_iterator_cc_api", + "//testing/base/public:gunit_main", + ], +) diff --git a/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator.rs b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator.rs new file mode 100644 index 000000000..78c331792 --- /dev/null +++ b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator.rs @@ -0,0 +1,138 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +pub struct MyContainer { + pub data: [i32; 3], +} + +pub struct MyContainerIntoIter { + data: [i32; 3], + index: usize, +} + +impl Iterator for MyContainerIntoIter { + type Item = i32; + fn next(&mut self) -> Option { + if self.index < self.data.len() { + let item = self.data[self.index]; + self.index += 1; + Some(item) + } else { + None + } + } +} + +impl IntoIterator for MyContainer { + type Item = i32; + type IntoIter = MyContainerIntoIter; + fn into_iter(self) -> Self::IntoIter { + MyContainerIntoIter { data: self.data, index: 0 } + } +} + +pub struct MyContainerIter<'a> { + data: &'a [i32], +} + +impl<'a> Iterator for MyContainerIter<'a> { + type Item = &'a i32; + fn next(&mut self) -> Option { + self.data.split_off_first() + } +} + +impl<'a> IntoIterator for &'a MyContainer { + type Item = &'a i32; + type IntoIter = MyContainerIter<'a>; + fn into_iter(self) -> Self::IntoIter { + MyContainerIter { data: &self.data } + } +} + +pub struct MyContainerIterMut<'a> { + data: &'a mut [i32], +} + +impl<'a> Iterator for MyContainerIterMut<'a> { + type Item = &'a mut i32; + fn next(&mut self) -> Option { + self.data.split_off_first_mut() + } +} + +impl<'a> IntoIterator for &'a mut MyContainer { + type Item = &'a mut i32; + type IntoIter = MyContainerIterMut<'a>; + fn into_iter(self) -> Self::IntoIter { + MyContainerIterMut { data: &mut self.data } + } +} + +pub fn make_container(a: i32, b: i32, c: i32) -> MyContainer { + MyContainer { data: [a, b, c] } +} + +pub struct MyIterator { + pub value: i32, +} + +impl Iterator for MyIterator { + type Item = i32; + fn next(&mut self) -> Option { + Some(self.value) + } +} + +pub struct ContainerWithRefIntoIter<'a> { + pub iter: &'a mut MyIterator, +} + +impl<'a> IntoIterator for ContainerWithRefIntoIter<'a> { + type Item = i32; + type IntoIter = &'a mut MyIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter + } +} + +pub struct ContainerWithInherentBegin { + pub data: [i32; 3], +} + +pub struct SimpleIntoIter { + pub val: i32, +} +impl Iterator for SimpleIntoIter { + type Item = i32; + fn next(&mut self) -> Option { + None + } +} + +impl IntoIterator for ContainerWithInherentBegin { + type Item = i32; + type IntoIter = SimpleIntoIter; + fn into_iter(self) -> Self::IntoIter { + SimpleIntoIter { val: 0 } + } +} + +impl ContainerWithInherentBegin { + pub fn begin(&self) -> i32 { + 42 + } +} + +pub fn make_inherent_container() -> ContainerWithInherentBegin { + ContainerWithInherentBegin { data: [1, 2, 3] } +} + +pub fn make_iterator(value: i32) -> MyIterator { + MyIterator { value } +} + +pub fn make_ref_container<'a>(iter: &'a mut MyIterator) -> ContainerWithRefIntoIter<'a> { + ContainerWithRefIntoIter { iter } +} diff --git a/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api.h b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api.h new file mode 100644 index 000000000..e193758f8 --- /dev/null +++ b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api.h @@ -0,0 +1,829 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Automatically @generated C++ bindings for the following Rust crate: +// into_iterator_rust_golden + +// clang-format off +#ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_KNOWN_TRAITS_INTO_ITERATOR_INTO_ITERATOR_RUST_GOLDEN +#define THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_KNOWN_TRAITS_INTO_ITERATOR_INTO_ITERATOR_RUST_GOLDEN + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +#pragma clang diagnostic ignored "-Wunused-private-field" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wignored-attributes" +#include "support/annotations_internal.h" +#include "support/bridge.h" +#include "support/internal/slot.h" +#include "support/lifetime_annotations.h" +#include "support/rs_std/iterator_adapter.h" +#include "support/rs_std/slice_ref.h" +#include "support/rs_std/traits.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "support/rs_std/rs_core.h" + +namespace into_iterator_rust { +struct MyContainer; +struct MyIterator; +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: ContainerWithInherentBegin") alignas(4) + [[clang::trivial_abi]] ContainerWithInherentBegin final { + public: + // `into_iterator_rust_golden::ContainerWithInherentBegin` doesn't implement + // the `Default` trait + ContainerWithInherentBegin() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~ContainerWithInherentBegin() = default; + ContainerWithInherentBegin(ContainerWithInherentBegin&&) = default; + ContainerWithInherentBegin& operator=(ContainerWithInherentBegin&&) = default; + + // `into_iterator_rust_golden::ContainerWithInherentBegin` doesn't implement + // the `Clone` trait + ContainerWithInherentBegin(const ContainerWithInherentBegin&) = delete; + ContainerWithInherentBegin& operator=(const ContainerWithInherentBegin&) = + delete; + ContainerWithInherentBegin(::crubit::UnsafeRelocateTag, + ContainerWithInherentBegin&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + + ::std::int32_t begin() const; + + union { + ::std::array<::std::int32_t, 3> data; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: ContainerWithRefIntoIter") alignas(8) + [[clang::trivial_abi]] ContainerWithRefIntoIter final { + public: + // `into_iterator_rust_golden::ContainerWithRefIntoIter` doesn't implement the + // `Default` trait + ContainerWithRefIntoIter() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~ContainerWithRefIntoIter() = default; + ContainerWithRefIntoIter(ContainerWithRefIntoIter&&) = default; + ContainerWithRefIntoIter& operator=(ContainerWithRefIntoIter&&) = default; + + // `into_iterator_rust_golden::ContainerWithRefIntoIter` doesn't implement the + // `Clone` trait + ContainerWithRefIntoIter(const ContainerWithRefIntoIter&) = delete; + ContainerWithRefIntoIter& operator=(const ContainerWithRefIntoIter&) = delete; + ContainerWithRefIntoIter(::crubit::UnsafeRelocateTag, + ContainerWithRefIntoIter&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + + // Error generating bindings for struct + // `into_iterator_rust_golden::ContainerWithRefIntoIter` defined at + // cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator.rs;l=88: + // IntoIterator/Iterator impls with generic type or const parameters are not + // supported yet. + + union { + ::into_iterator_rust::MyIterator* crubit_nonnull iter; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: MyContainerIntoIter") alignas(8) + [[clang::trivial_abi]] MyContainerIntoIter final { + public: + // `into_iterator_rust_golden::MyContainerIntoIter` doesn't implement the + // `Default` trait + MyContainerIntoIter() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~MyContainerIntoIter() = default; + MyContainerIntoIter(MyContainerIntoIter&&) = default; + MyContainerIntoIter& operator=(MyContainerIntoIter&&) = default; + + // `into_iterator_rust_golden::MyContainerIntoIter` doesn't implement the + // `Clone` trait + MyContainerIntoIter(const MyContainerIntoIter&) = delete; + MyContainerIntoIter& operator=(const MyContainerIntoIter&) = delete; + MyContainerIntoIter(::crubit::UnsafeRelocateTag, + MyContainerIntoIter&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + + private: + union { + ::std::uintptr_t index; + }; + union { + ::std::array<::std::int32_t, 3> data; + }; + unsigned char __padding0[4]; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: MyContainerIter") alignas(8) + [[clang::trivial_abi]] MyContainerIter final { + public: + // `into_iterator_rust_golden::MyContainerIter` doesn't implement the + // `Default` trait + MyContainerIter() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~MyContainerIter() = default; + MyContainerIter(MyContainerIter&&) = default; + MyContainerIter& operator=(MyContainerIter&&) = default; + + // `into_iterator_rust_golden::MyContainerIter` doesn't implement the `Clone` + // trait + MyContainerIter(const MyContainerIter&) = delete; + MyContainerIter& operator=(const MyContainerIter&) = delete; + MyContainerIter(::crubit::UnsafeRelocateTag, MyContainerIter&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + + private: + union { + rs_std::SliceRef data; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: MyContainerIterMut") alignas(8) + [[clang::trivial_abi]] MyContainerIterMut final { + public: + // `into_iterator_rust_golden::MyContainerIterMut` doesn't implement the + // `Default` trait + MyContainerIterMut() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~MyContainerIterMut() = default; + MyContainerIterMut(MyContainerIterMut&&) = default; + MyContainerIterMut& operator=(MyContainerIterMut&&) = default; + + // `into_iterator_rust_golden::MyContainerIterMut` doesn't implement the + // `Clone` trait + MyContainerIterMut(const MyContainerIterMut&) = delete; + MyContainerIterMut& operator=(const MyContainerIterMut&) = delete; + MyContainerIterMut(::crubit::UnsafeRelocateTag, MyContainerIterMut&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + + private: + union { + rs_std::SliceRef<::std::int32_t> data; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: MyIterator") alignas(4) + [[clang::trivial_abi]] MyIterator final { + public: + // `into_iterator_rust_golden::MyIterator` doesn't implement the `Default` + // trait + MyIterator() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~MyIterator() = default; + MyIterator(MyIterator&&) = default; + MyIterator& operator=(MyIterator&&) = default; + + // `into_iterator_rust_golden::MyIterator` doesn't implement the `Clone` trait + MyIterator(const MyIterator&) = delete; + MyIterator& operator=(const MyIterator&) = delete; + MyIterator(::crubit::UnsafeRelocateTag, MyIterator&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + union { + ::std::int32_t value; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: SimpleIntoIter") alignas(4) + [[clang::trivial_abi]] SimpleIntoIter final { + public: + // `into_iterator_rust_golden::SimpleIntoIter` doesn't implement the `Default` + // trait + SimpleIntoIter() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~SimpleIntoIter() = default; + SimpleIntoIter(SimpleIntoIter&&) = default; + SimpleIntoIter& operator=(SimpleIntoIter&&) = default; + + // `into_iterator_rust_golden::SimpleIntoIter` doesn't implement the `Clone` + // trait + SimpleIntoIter(const SimpleIntoIter&) = delete; + SimpleIntoIter& operator=(const SimpleIntoIter&) = delete; + SimpleIntoIter(::crubit::UnsafeRelocateTag, SimpleIntoIter&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + union { + ::std::int32_t val; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +::into_iterator_rust::MyContainer make_container(::std::int32_t a, + ::std::int32_t b, + ::std::int32_t c); + +::into_iterator_rust::ContainerWithInherentBegin make_inherent_container(); + +::into_iterator_rust::MyIterator make_iterator(::std::int32_t value); + +::into_iterator_rust::ContainerWithRefIntoIter make_ref_container( + ::into_iterator_rust::MyIterator* $a crubit_nonnull iter); + +} // namespace into_iterator_rust + +template <> +struct rs_std::impl<::into_iterator_rust::ContainerWithInherentBegin, + ::rs::core::iter::IntoIterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + "::Item") = ::std::int32_t; + using IntoIter CRUBIT_INTERNAL_RUST_TYPE( + "::IntoIter") = ::into_iterator_rust::SimpleIntoIter; + + static ::into_iterator_rust::SimpleIntoIter into_iter( + ::into_iterator_rust::ContainerWithInherentBegin self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::ContainerWithRefIntoIter, + ::rs::core::iter::IntoIterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + " as :: core :: " + "iter :: IntoIterator>::Item") = ::std::int32_t; + using IntoIter CRUBIT_INTERNAL_RUST_TYPE( + " as :: core :: " + "iter :: IntoIterator>::IntoIter") = + ::into_iterator_rust::MyIterator* $a crubit_nonnull; + + static ::into_iterator_rust::MyIterator& $a + into_iter(::into_iterator_rust::ContainerWithRefIntoIter self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::MyContainerIntoIter, + ::rs::core::iter::Iterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + "::Item") = ::std::int32_t; + + static ::std::optional<::std::int32_t> next( + ::into_iterator_rust::MyContainerIntoIter& self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::MyContainerIter, + ::rs::core::iter::Iterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + " as :: core :: iter :: " + "Iterator>::Item") = ::std::int32_t const* $a crubit_nonnull; + + static ::std::optional<::std::int32_t const * $a crubit_nonnull> next( + ::into_iterator_rust::MyContainerIter& self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::MyContainerIterMut, + ::rs::core::iter::Iterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + " as :: core :: iter " + ":: Iterator>::Item") = ::std::int32_t* $a crubit_nonnull; + + static ::std::optional<::std::int32_t* $a crubit_nonnull> next( + ::into_iterator_rust::MyContainerIterMut& self); +}; + +namespace into_iterator_rust { + +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: into_iterator_rust_golden :: MyContainer") alignas(4) + [[clang::trivial_abi]] MyContainer final { + public: + // `into_iterator_rust_golden::MyContainer` doesn't implement the `Default` + // trait + MyContainer() = delete; + + // No custom `Drop` impl and no custom "drop glue" required + ~MyContainer() = default; + MyContainer(MyContainer&&) = default; + MyContainer& operator=(MyContainer&&) = default; + + // `into_iterator_rust_golden::MyContainer` doesn't implement the `Clone` + // trait + MyContainer(const MyContainer&) = delete; + MyContainer& operator=(const MyContainer&) = delete; + MyContainer(::crubit::UnsafeRelocateTag, MyContainer&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + rs::IteratorAdapter<::into_iterator_rust::MyContainerIntoIter> begin() &&; + rs::IteratorEnd end() &&; + rs::IteratorAdapter<::into_iterator_rust::MyContainerIter> begin() const&; + rs::IteratorEnd end() const&; + rs::IteratorAdapter<::into_iterator_rust::MyContainerIterMut> begin() &; + rs::IteratorEnd end() &; + union { + ::std::array<::std::int32_t, 3> data; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +} // namespace into_iterator_rust + +template <> +struct rs_std::impl<::into_iterator_rust::MyContainer, + ::rs::core::iter::IntoIterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + "::Item") = ::std::int32_t; + using IntoIter CRUBIT_INTERNAL_RUST_TYPE( + "::IntoIter") = ::into_iterator_rust::MyContainerIntoIter; + + static ::into_iterator_rust::MyContainerIntoIter into_iter( + ::into_iterator_rust::MyContainer self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::MyIterator, + ::rs::core::iter::Iterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + "::Item") = ::std::int32_t; + + static ::std::optional<::std::int32_t> next( + ::into_iterator_rust::MyIterator& self); +}; + +template <> +struct rs_std::impl<::into_iterator_rust::SimpleIntoIter, + ::rs::core::iter::Iterator> { + static constexpr bool kIsImplemented = true; + using Item CRUBIT_INTERNAL_RUST_TYPE( + "::Item") = ::std::int32_t; + + static ::std::optional<::std::int32_t> next( + ::into_iterator_rust::SimpleIntoIter& self); +}; + +namespace into_iterator_rust { + +static_assert( + sizeof(ContainerWithInherentBegin) == 12, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(ContainerWithInherentBegin) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::ContainerWithInherentBegin>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::ContainerWithInherentBegin>); +namespace __crubit_internal { +extern "C" ::std::int32_t __crubit_thunk_begin( + ::into_iterator_rust::ContainerWithInherentBegin const&); +} +inline ::std::int32_t ContainerWithInherentBegin::begin() const { + auto&& self = *this; + return __crubit_internal::__crubit_thunk_begin(self); +} +inline void ContainerWithInherentBegin::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(ContainerWithInherentBegin, data)); +} +static_assert( + sizeof(ContainerWithRefIntoIter) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(ContainerWithRefIntoIter) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::ContainerWithRefIntoIter>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::ContainerWithRefIntoIter>); +inline void ContainerWithRefIntoIter::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(ContainerWithRefIntoIter, iter)); +} +static_assert( + sizeof(MyContainer) == 12, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(MyContainer) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::MyContainer>); +static_assert( + ::std::is_trivially_move_assignable_v<::into_iterator_rust::MyContainer>); +namespace __crubit_internal { +extern "C" void __crubit_thunk_into_uiter( + ::into_iterator_rust::MyContainer*, + ::into_iterator_rust::MyContainerIntoIter* __ret_ptr); +} +inline rs::IteratorAdapter<::into_iterator_rust::MyContainerIntoIter> +MyContainer::begin() && { + MyContainer&& self_ = ::std::move(*this); + auto call_into_iter = [&]() -> decltype(auto) { + crubit::Slot<::into_iterator_rust::MyContainerIntoIter> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_into_uiter(&self_, + __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); + }; + return rs::IteratorAdapter<::into_iterator_rust::MyContainerIntoIter>( + call_into_iter()); +} +inline rs::IteratorEnd MyContainer::end() && { return rs::IteratorEnd(); } +namespace __crubit_internal { +extern "C" void __crubit_thunk_into_uiter( + ::into_iterator_rust::MyContainer const&, + ::into_iterator_rust::MyContainerIter* __ret_ptr); +} +inline rs::IteratorAdapter<::into_iterator_rust::MyContainerIter> +MyContainer::begin() const& { + const MyContainer& self_ = *this; + auto call_into_iter = [&]() -> decltype(auto) { + crubit::Slot<::into_iterator_rust::MyContainerIter> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_into_uiter(self_, __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); + }; + return rs::IteratorAdapter<::into_iterator_rust::MyContainerIter>( + call_into_iter()); +} +inline rs::IteratorEnd MyContainer::end() const& { return rs::IteratorEnd(); } +namespace __crubit_internal { +extern "C" void __crubit_thunk_into_uiter( + ::into_iterator_rust::MyContainer&, + ::into_iterator_rust::MyContainerIterMut* __ret_ptr); +} +inline rs::IteratorAdapter<::into_iterator_rust::MyContainerIterMut> +MyContainer::begin() & { + MyContainer& self_ = *this; + auto call_into_iter = [&]() -> decltype(auto) { + crubit::Slot<::into_iterator_rust::MyContainerIterMut> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_into_uiter(self_, __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); + }; + return rs::IteratorAdapter<::into_iterator_rust::MyContainerIterMut>( + call_into_iter()); +} +inline rs::IteratorEnd MyContainer::end() & { return rs::IteratorEnd(); } +inline void MyContainer::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(MyContainer, data)); +} +static_assert( + sizeof(MyContainerIntoIter) == 24, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(MyContainerIntoIter) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::MyContainerIntoIter>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::MyContainerIntoIter>); +inline void MyContainerIntoIter::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(MyContainerIntoIter, index)); + static_assert(8 == offsetof(MyContainerIntoIter, data)); +} +static_assert( + sizeof(MyContainerIter) == 16, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(MyContainerIter) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::MyContainerIter>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::MyContainerIter>); +inline void MyContainerIter::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(MyContainerIter, data)); +} +static_assert( + sizeof(MyContainerIterMut) == 16, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(MyContainerIterMut) == 8, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::MyContainerIterMut>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::MyContainerIterMut>); +inline void MyContainerIterMut::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(MyContainerIterMut, data)); +} +static_assert( + sizeof(MyIterator) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(MyIterator) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert( + ::std::is_trivially_move_constructible_v<::into_iterator_rust::MyIterator>); +static_assert( + ::std::is_trivially_move_assignable_v<::into_iterator_rust::MyIterator>); +inline void MyIterator::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(MyIterator, value)); +} +static_assert( + sizeof(SimpleIntoIter) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(SimpleIntoIter) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert(::std::is_trivially_destructible_v); +static_assert(::std::is_trivially_move_constructible_v< + ::into_iterator_rust::SimpleIntoIter>); +static_assert(::std::is_trivially_move_assignable_v< + ::into_iterator_rust::SimpleIntoIter>); +inline void SimpleIntoIter::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(SimpleIntoIter, val)); +} +namespace __crubit_internal { +extern "C" void __crubit_thunk_make_ucontainer( + ::std::int32_t, ::std::int32_t, ::std::int32_t, + ::into_iterator_rust::MyContainer* __ret_ptr); +} +inline ::into_iterator_rust::MyContainer make_container(::std::int32_t a, + ::std::int32_t b, + ::std::int32_t c) { + crubit::Slot<::into_iterator_rust::MyContainer> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_make_ucontainer(a, b, c, + __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_make_uinherent_ucontainer( + ::into_iterator_rust::ContainerWithInherentBegin* __ret_ptr); +} +inline ::into_iterator_rust::ContainerWithInherentBegin +make_inherent_container() { + crubit::Slot<::into_iterator_rust::ContainerWithInherentBegin> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_make_uinherent_ucontainer( + __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_make_uiterator( + ::std::int32_t, ::into_iterator_rust::MyIterator* __ret_ptr); +} +inline ::into_iterator_rust::MyIterator make_iterator(::std::int32_t value) { + crubit::Slot<::into_iterator_rust::MyIterator> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_make_uiterator(value, + __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_make_uref_ucontainer( + ::into_iterator_rust::MyIterator* $a crubit_nonnull, + ::into_iterator_rust::ContainerWithRefIntoIter* __ret_ptr); +} +inline ::into_iterator_rust::ContainerWithRefIntoIter make_ref_container( + ::into_iterator_rust::MyIterator* $a crubit_nonnull iter) { + crubit::Slot<::into_iterator_rust::ContainerWithRefIntoIter> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_make_uref_ucontainer( + iter, __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +} // namespace into_iterator_rust + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithInherentBegin( + ::into_iterator_rust::ContainerWithInherentBegin*, + ::into_iterator_rust::SimpleIntoIter* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::into_iterator_rust::SimpleIntoIter +rs_std::impl<::into_iterator_rust::ContainerWithInherentBegin, + ::rs::core::iter::IntoIterator>:: + into_iter(::into_iterator_rust::ContainerWithInherentBegin self) { + crubit::Slot<::into_iterator_rust::SimpleIntoIter> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + into_iterator_rust::__crubit_internal:: + __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithInherentBegin( + &self, __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" ::into_iterator_rust::MyIterator& $a +__crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithRefIntoIter_x0000003c_x00000027a_x0000003e( + ::into_iterator_rust::ContainerWithRefIntoIter*); +} +} // namespace into_iterator_rust +inline ::into_iterator_rust::MyIterator& $a +rs_std::impl<::into_iterator_rust::ContainerWithRefIntoIter, + ::rs::core::iter::IntoIterator>:: + into_iter(::into_iterator_rust::ContainerWithRefIntoIter self) { + return into_iterator_rust::__crubit_internal:: + __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithRefIntoIter_x0000003c_x00000027a_x0000003e( + &self); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainer( + ::into_iterator_rust::MyContainer*, + ::into_iterator_rust::MyContainerIntoIter* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::into_iterator_rust::MyContainerIntoIter rs_std::impl< + ::into_iterator_rust::MyContainer, + ::rs::core::iter::IntoIterator>::into_iter(::into_iterator_rust::MyContainer + self) { + crubit::Slot<::into_iterator_rust::MyContainerIntoIter> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + into_iterator_rust::__crubit_internal:: + __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainer( + &self, __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIntoIter( + ::into_iterator_rust::MyContainerIntoIter&, unsigned char* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::std::optional<::std::int32_t> rs_std::impl< + ::into_iterator_rust::MyContainerIntoIter, + ::rs::core::iter::Iterator>::next(::into_iterator_rust::MyContainerIntoIter& + self) { + unsigned char __return_value_storage + [::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>::kSize]; + into_iterator_rust::__crubit_internal:: + __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIntoIter( + self, __return_value_storage); + return ::crubit::internal::Decode< + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>>( + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>( + ::crubit::TransmuteAbi<::std::int32_t>()), + __return_value_storage); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIter_x0000003c_x00000027a_x0000003e( + ::into_iterator_rust::MyContainerIter&, unsigned char* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::std::optional<::std::int32_t const * $a crubit_nonnull> rs_std::impl< + ::into_iterator_rust::MyContainerIter, + ::rs::core::iter::Iterator>::next(::into_iterator_rust::MyContainerIter& + self) { + unsigned char + __return_value_storage[::crubit::OptionAbi<::crubit::TransmuteAbi< + ::std::int32_t const * $static crubit_nonnull>>::kSize]; + into_iterator_rust::__crubit_internal:: + __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIter_x0000003c_x00000027a_x0000003e( + self, __return_value_storage); + return ::crubit::internal::Decode<::crubit::OptionAbi< + ::crubit::TransmuteAbi<::std::int32_t const * $static crubit_nonnull>>>( + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t const * + $static crubit_nonnull>>( + ::crubit::TransmuteAbi<::std::int32_t const * + $static crubit_nonnull>()), + __return_value_storage); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIterMut_x0000003c_x00000027a_x0000003e( + ::into_iterator_rust::MyContainerIterMut&, unsigned char* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::std::optional<::std::int32_t* $a crubit_nonnull> rs_std::impl< + ::into_iterator_rust::MyContainerIterMut, + ::rs::core::iter::Iterator>::next(::into_iterator_rust::MyContainerIterMut& + self) { + unsigned char __return_value_storage[::crubit::OptionAbi< + ::crubit::TransmuteAbi<::std::int32_t* $static crubit_nonnull>>::kSize]; + into_iterator_rust::__crubit_internal:: + __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIterMut_x0000003c_x00000027a_x0000003e( + self, __return_value_storage); + return ::crubit::internal::Decode<::crubit::OptionAbi< + ::crubit::TransmuteAbi<::std::int32_t* $static crubit_nonnull>>>( + ::crubit::OptionAbi< + ::crubit::TransmuteAbi<::std::int32_t* $static crubit_nonnull>>( + ::crubit::TransmuteAbi<::std::int32_t* $static crubit_nonnull>()), + __return_value_storage); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyIterator( + ::into_iterator_rust::MyIterator&, unsigned char* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::std::optional<::std::int32_t> rs_std::impl< + ::into_iterator_rust::MyIterator, + ::rs::core::iter::Iterator>::next(::into_iterator_rust::MyIterator& self) { + unsigned char __return_value_storage + [::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>::kSize]; + into_iterator_rust::__crubit_internal:: + __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyIterator( + self, __return_value_storage); + return ::crubit::internal::Decode< + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>>( + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>( + ::crubit::TransmuteAbi<::std::int32_t>()), + __return_value_storage); +} + +namespace into_iterator_rust { +namespace __crubit_internal { +extern "C" void +__crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aSimpleIntoIter( + ::into_iterator_rust::SimpleIntoIter&, unsigned char* __ret_ptr); +} +} // namespace into_iterator_rust +inline ::std::optional<::std::int32_t> +rs_std::impl<::into_iterator_rust::SimpleIntoIter, ::rs::core::iter::Iterator>:: + next(::into_iterator_rust::SimpleIntoIter& self) { + unsigned char __return_value_storage + [::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>::kSize]; + into_iterator_rust::__crubit_internal:: + __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aSimpleIntoIter( + self, __return_value_storage); + return ::crubit::internal::Decode< + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>>( + ::crubit::OptionAbi<::crubit::TransmuteAbi<::std::int32_t>>( + ::crubit::TransmuteAbi<::std::int32_t>()), + __return_value_storage); +} + +#pragma clang diagnostic pop +#endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_KNOWN_TRAITS_INTO_ITERATOR_INTO_ITERATOR_RUST_GOLDEN diff --git a/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api_impl.rs b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api_impl.rs new file mode 100644 index 000000000..a710e1262 --- /dev/null +++ b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_cc_api_impl.rs @@ -0,0 +1,261 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// Automatically @generated C++ bindings for the following Rust crate: +// into_iterator_rust_golden + +#![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] +#![allow(improper_ctypes_definitions)] +#![deny(warnings)] + +extern crate alloc; +extern crate core; +const _: () = + assert!(::std::mem::size_of::<::into_iterator_rust_golden::ContainerWithInherentBegin>() == 12); +const _: () = + assert!(::std::mem::align_of::<::into_iterator_rust_golden::ContainerWithInherentBegin>() == 4); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_begin( + __self: &'static ::into_iterator_rust_golden::ContainerWithInherentBegin, +) -> i32 { + unsafe { ::into_iterator_rust_golden::ContainerWithInherentBegin::begin(__self) } +} +const _: () = assert!( + ::core::mem::offset_of!(::into_iterator_rust_golden::ContainerWithInherentBegin, data) == 0 +); +const _: () = + assert!(::std::mem::size_of::<::into_iterator_rust_golden::ContainerWithRefIntoIter>() == 8); +const _: () = + assert!(::std::mem::align_of::<::into_iterator_rust_golden::ContainerWithRefIntoIter>() == 8); +const _: () = assert!( + ::core::mem::offset_of!(::into_iterator_rust_golden::ContainerWithRefIntoIter, iter) == 0 +); +const _: () = assert!(::std::mem::size_of::<::into_iterator_rust_golden::MyContainer>() == 12); +const _: () = assert!(::std::mem::align_of::<::into_iterator_rust_golden::MyContainer>() == 4); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_into_uiter( + __self: &'static mut ::core::mem::MaybeUninit<::into_iterator_rust_golden::MyContainer>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __self = __self.assume_init_read(); + let __rs_return_value = + <::into_iterator_rust_golden::MyContainer as ::core::iter::IntoIterator>::into_iter( + __self, + ); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyContainerIntoIter) + .write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_into_uiter( + __self: &'static ::into_iterator_rust_golden::MyContainer, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value=<&'static::into_iterator_rust_golden::MyContainer as::core::iter::IntoIterator>::into_iter(__self); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyContainerIter<'static>) + .write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_into_uiter( + __self: &'static mut ::into_iterator_rust_golden::MyContainer, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value=<&'static mut::into_iterator_rust_golden::MyContainer as::core::iter::IntoIterator>::into_iter(__self); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyContainerIterMut<'static>) + .write(__rs_return_value); + } +} +const _: () = assert!(::core::mem::offset_of!(::into_iterator_rust_golden::MyContainer, data) == 0); +const _: () = + assert!(::std::mem::size_of::<::into_iterator_rust_golden::MyContainerIntoIter>() == 24); +const _: () = + assert!(::std::mem::align_of::<::into_iterator_rust_golden::MyContainerIntoIter>() == 8); +const _: () = assert!(::std::mem::size_of::<::into_iterator_rust_golden::MyContainerIter>() == 16); +const _: () = assert!(::std::mem::align_of::<::into_iterator_rust_golden::MyContainerIter>() == 8); +const _: () = + assert!(::std::mem::size_of::<::into_iterator_rust_golden::MyContainerIterMut>() == 16); +const _: () = + assert!(::std::mem::align_of::<::into_iterator_rust_golden::MyContainerIterMut>() == 8); +const _: () = assert!(::std::mem::size_of::<::into_iterator_rust_golden::MyIterator>() == 4); +const _: () = assert!(::std::mem::align_of::<::into_iterator_rust_golden::MyIterator>() == 4); +const _: () = assert!(::core::mem::offset_of!(::into_iterator_rust_golden::MyIterator, value) == 0); +const _: () = assert!(::std::mem::size_of::<::into_iterator_rust_golden::SimpleIntoIter>() == 4); +const _: () = assert!(::std::mem::align_of::<::into_iterator_rust_golden::SimpleIntoIter>() == 4); +const _: () = + assert!(::core::mem::offset_of!(::into_iterator_rust_golden::SimpleIntoIter, val) == 0); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_make_ucontainer( + a: i32, + b: i32, + c: i32, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = ::into_iterator_rust_golden::make_container(a, b, c); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyContainer).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_make_uinherent_ucontainer( + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = ::into_iterator_rust_golden::make_inherent_container(); + (__ret_ptr as *mut ::into_iterator_rust_golden::ContainerWithInherentBegin) + .write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_make_uiterator( + value: i32, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = ::into_iterator_rust_golden::make_iterator(value); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyIterator).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_make_uref_ucontainer( + iter: &'static mut ::into_iterator_rust_golden::MyIterator, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = ::into_iterator_rust_golden::make_ref_container(iter); + (__ret_ptr as *mut ::into_iterator_rust_golden::ContainerWithRefIntoIter<'static>) + .write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithInherentBegin( + __self: &'static mut ::core::mem::MaybeUninit< + ::into_iterator_rust_golden::ContainerWithInherentBegin, + >, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __self = __self.assume_init_read(); + let __rs_return_value=<::into_iterator_rust_golden::ContainerWithInherentBegin as::core::iter::IntoIterator>::into_iter(__self); + (__ret_ptr as *mut ::into_iterator_rust_golden::SimpleIntoIter).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aContainerWithRefIntoIter_x0000003c_x00000027a_x0000003e( + __self: &'static mut ::core::mem::MaybeUninit< + ::into_iterator_rust_golden::ContainerWithRefIntoIter<'static>, + >, +) -> &'static mut ::into_iterator_rust_golden::MyIterator { + unsafe { + let __self = __self.assume_init_read(); + <::into_iterator_rust_golden::ContainerWithRefIntoIter as::core::iter::IntoIterator>::into_iter(__self) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_IntoIterator_uinto_uiter_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainer( + __self: &'static mut ::core::mem::MaybeUninit<::into_iterator_rust_golden::MyContainer>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __self = __self.assume_init_read(); + let __rs_return_value = + <::into_iterator_rust_golden::MyContainer as ::core::iter::IntoIterator>::into_iter( + __self, + ); + (__ret_ptr as *mut ::into_iterator_rust_golden::MyContainerIntoIter) + .write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIntoIter( + __self: &'static mut ::into_iterator_rust_golden::MyContainerIntoIter, + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + <::into_iterator_rust_golden::MyContainerIntoIter as ::core::iter::Iterator>::next( + __self, + ); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIter_x0000003c_x00000027a_x0000003e( + __self: &'static mut ::into_iterator_rust_golden::MyContainerIter<'static>, + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + <::into_iterator_rust_golden::MyContainerIter as ::core::iter::Iterator>::next(__self); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::<&'static i32>()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyContainerIterMut_x0000003c_x00000027a_x0000003e( + __self: &'static mut ::into_iterator_rust_golden::MyContainerIterMut<'static>, + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + <::into_iterator_rust_golden::MyContainerIterMut as ::core::iter::Iterator>::next( + __self, + ); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::<&'static mut i32>()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aMyIterator( + __self: &'static mut ::into_iterator_rust_golden::MyIterator, + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + <::into_iterator_rust_golden::MyIterator as ::core::iter::Iterator>::next(__self); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_Iterator_unext_uinto_uiterator_urust_ugolden_x0000003a_x0000003aSimpleIntoIter( + __self: &'static mut ::into_iterator_rust_golden::SimpleIntoIter, + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + <::into_iterator_rust_golden::SimpleIntoIter as ::core::iter::Iterator>::next(__self); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} diff --git a/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_test.cc b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_test.cc new file mode 100644 index 000000000..1d55064cb --- /dev/null +++ b/cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_test.cc @@ -0,0 +1,73 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +#include "gtest/gtest.h" +#include "cc_bindings_from_rs/test/known_traits/into_iterator/into_iterator_rust.h" + +namespace { + +using ::into_iterator_rust::ContainerWithInherentBegin; +using ::into_iterator_rust::ContainerWithRefIntoIter; +using ::into_iterator_rust::make_container; +using ::into_iterator_rust::make_inherent_container; +using ::into_iterator_rust::MyContainer; + +static_assert(std::ranges::range); +static_assert(std::ranges::range); +static_assert(std::ranges::range); + +static_assert(std::ranges::input_range); +static_assert(std::ranges::input_range); +static_assert(std::ranges::input_range); + +static_assert(!std::ranges::range); +static_assert(!std::ranges::range); + +TEST(IntoIteratorTest, ValueContainer) { + MyContainer c = make_container(10, 20, 30); + int count = 0; + int sum = 0; + for (int x : std::move(c)) { + count++; + sum += x; + } + EXPECT_EQ(count, 3); + EXPECT_EQ(sum, 60); +} + +TEST(IntoIteratorTest, SharedRefContainer) { + MyContainer c = make_container(10, 20, 30); + const MyContainer& const_c = c; + int count = 0; + int sum = 0; + for (const int& x : const_c) { + count++; + sum += x; + } + EXPECT_EQ(count, 3); + EXPECT_EQ(sum, 60); +} + +TEST(IntoIteratorTest, MutRefContainer) { + MyContainer c = make_container(10, 20, 30); + for (int& x : c) { + x *= 2; + } + + int sum = 0; + for (int x : std::move(c)) { + sum += x; + } + EXPECT_EQ(sum, 120); +} + +TEST(IntoIteratorTest, InherentBeginConflict) { + ContainerWithInherentBegin c = make_inherent_container(); + EXPECT_EQ(c.begin(), 42); +} + +} // namespace diff --git a/cc_bindings_from_rs/test/traits/stdlib/stdlib_test.cc b/cc_bindings_from_rs/test/traits/stdlib/stdlib_test.cc index 1a390499b..ac57028e0 100644 --- a/cc_bindings_from_rs/test/traits/stdlib/stdlib_test.cc +++ b/cc_bindings_from_rs/test/traits/stdlib/stdlib_test.cc @@ -83,19 +83,15 @@ static_assert(std::input_iterator>); using RefIterator = rs::IteratorAdapter; using RefTraits = std::iterator_traits; -static_assert(std::is_same_v); -static_assert( - std::is_same_v); +static_assert(std::is_same_v); +static_assert(std::is_same_v); TEST(StdlibTraitTest, RefIteratorAdapter) { std::vector data = {10, 20, 30}; auto s = stdlib::RefIterator::new_(rs_std::SliceRef(data)); std::vector v; - std::ranges::copy( - std::ranges::subrange(rs::IteratorAdapter(std::move(s)), - rs::IteratorEnd{}) | - std::views::transform([](const int32_t* p) { return *p; }), - std::back_inserter(v)); + std::ranges::copy(rs::IteratorAdapter(std::move(s)), rs::IteratorEnd{}, + std::back_inserter(v)); EXPECT_THAT(v, testing::ElementsAre(10, 20, 30)); } diff --git a/support/rs_std/iterator_adapter.h b/support/rs_std/iterator_adapter.h index b6c78736b..5aa6784cc 100644 --- a/support/rs_std/iterator_adapter.h +++ b/support/rs_std/iterator_adapter.h @@ -50,19 +50,23 @@ struct IteratorEnd { // functionality conditonally - if `TAdaptedIterator` is `Clone` (which // presumably would ensure that `next()` doesn't affect the other copy?). template - requires(rs_std::where_v && - std::movable && - std::movable::Item>) + requires(rs_std::where_v) + class IteratorAdapter { private: using impl = rs_std::impl; + static constexpr bool kIsPointerItem = std::is_pointer_v; public: - using value_type = impl::Item; + using value_type = + std::conditional_t, + typename impl::Item>; using difference_type = std::ptrdiff_t; using pointer = void; - using reference = const value_type&; + using reference = std::conditional_t, + const value_type&>; using iterator_category = std::input_iterator_tag; using iterator_concept = std::input_iterator_tag; @@ -110,9 +114,19 @@ class IteratorAdapter { // a `const value_type&` and not `value_type&` (the former cannot be moved // out of). `iter_move` has to move out of `current_item_`, so we mark // `current_item_` as `mutable` to reconcile all of these requirements. - const value_type& operator*() const { return current_item_.value(); } + reference operator*() const { + if constexpr (kIsPointerItem) { + return *current_item_.value(); + } else { + return current_item_.value(); + } + } friend value_type&& iter_move(const IteratorAdapter& self) noexcept { - return std::move(*self.current_item_); + if constexpr (kIsPointerItem) { + return std::move(*self.current_item_.value()); + } else { + return std::move(*self.current_item_); + } } IteratorAdapter& operator++() { next(); @@ -127,7 +141,7 @@ class IteratorAdapter { TAdaptedIterator source_; // `mutable` to support `iter_move` taking a `const IteratorAdapter&`. - mutable std::optional current_item_; + mutable std::optional current_item_; }; template @@ -135,4 +149,19 @@ IteratorAdapter(TAdaptedIterator) -> IteratorAdapter; } // namespace rs +namespace rs_std { +// Mirrors `impl Iterator for &mut I` from the Rust +// standard library, which is needed because we don't automatically generate +// bindings for blanket impls today. +template + requires(rs_std::where_v) +struct impl { + static constexpr bool kIsImplemented = true; + using Item = typename rs_std::impl::Item; + static inline std::optional next(T* self) { + return rs_std::impl::next(*self); + } +}; +} // namespace rs_std + #endif // CRUBIT_SUPPORT_RS_STD_ITERATOR_ADAPTER_H_