diff --git a/macros/src/lib.rs b/macros/src/lib.rs index bf60f382..f4dfec40 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -14,6 +14,8 @@ extern crate proc_macro; +use std::borrow::Cow; + use proc_macro::TokenStream; use proc_macro2::Span; use proc_macro2::TokenStream as TokenStream2; @@ -54,14 +56,15 @@ fn derive_bundle_(input: DeriveInput) -> Result { )) } }; - let (tys, fields) = struct_fields(&data.fields); + let (tys, field_members) = struct_fields(&data.fields); + let field_idents = member_as_idents(&field_members); - let dyn_bundle_code = gen_dynamic_bundle_impl(&ident, &fields, &tys); + let dyn_bundle_code = gen_dynamic_bundle_impl(&ident, &field_members, &tys); let num_tys = tys.len(); let bundle_code = if num_tys == 0 { gen_unit_struct_bundle_impl(ident) } else { - gen_bundle_impl(&ident, &fields, &tys) + gen_bundle_impl(&ident, &field_members, &field_idents, &tys) }; let mut ts = dyn_bundle_code; ts.extend(bundle_code); @@ -70,7 +73,7 @@ fn derive_bundle_(input: DeriveInput) -> Result { fn gen_dynamic_bundle_impl( ident: &syn::Ident, - fields: &[syn::Ident], + field_members: &[syn::Member], tys: &[&syn::Type], ) -> TokenStream2 { quote! { @@ -86,15 +89,20 @@ fn gen_dynamic_bundle_impl( #[allow(clippy::forget_copy)] unsafe fn put(mut self, mut f: impl ::std::ops::FnMut(*mut u8, ::hecs::TypeInfo)) { #( - f((&mut self.#fields as *mut #tys).cast::(), ::hecs::TypeInfo::of::<#tys>()); - ::std::mem::forget(self.#fields); + f((&mut self.#field_members as *mut #tys).cast::(), ::hecs::TypeInfo::of::<#tys>()); + ::std::mem::forget(self.#field_members); )* } } } } -fn gen_bundle_impl(ident: &syn::Ident, fields: &[syn::Ident], tys: &[&syn::Type]) -> TokenStream2 { +fn gen_bundle_impl( + ident: &syn::Ident, + field_members: &[syn::Member], + field_idents: &[Cow], + tys: &[&syn::Type], +) -> TokenStream2 { let num_tys = tys.len(); quote! { impl ::hecs::Bundle for #ident { @@ -113,7 +121,6 @@ fn gen_bundle_impl(ident: &syn::Ident, fields: &[syn::Ident], tys: &[&syn::Type] ::std::cmp::Ord::cmp(&x.0, &y.0) .reverse() .then(::std::cmp::Ord::cmp(&x.1, &y.1)) - //x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)) }); let mut ids = [::std::any::TypeId::of::<()>(); #num_tys]; for (id, info) in ::std::iter::Iterator::zip(ids.iter_mut(), tys.iter()) { @@ -136,12 +143,12 @@ fn gen_bundle_impl(ident: &syn::Ident, fields: &[syn::Ident], tys: &[&syn::Type] mut f: impl ::std::ops::FnMut(::hecs::TypeInfo) -> ::std::option::Option<::std::ptr::NonNull>, ) -> ::std::result::Result { #( - let #fields = f(::hecs::TypeInfo::of::<#tys>()) + let #field_idents = f(::hecs::TypeInfo::of::<#tys>()) .ok_or_else(::hecs::MissingComponent::new::<#tys>)? .cast::<#tys>() .as_ptr(); )* - ::std::result::Result::Ok(Self { #( #fields: #fields.read(), )* }) + ::std::result::Result::Ok(Self { #( #field_members: #field_idents.read(), )* }) } } } @@ -163,19 +170,39 @@ fn gen_unit_struct_bundle_impl(ident: syn::Ident) -> TokenStream2 { } } -fn struct_fields(fields: &syn::Fields) -> (Vec<&syn::Type>, Vec) { +fn struct_fields(fields: &syn::Fields) -> (Vec<&syn::Type>, Vec) { match fields { syn::Fields::Named(ref fields) => fields .named .iter() - .map(|f| (&f.ty, f.ident.clone().unwrap())) + .map(|f| (&f.ty, syn::Member::Named(f.ident.clone().unwrap()))) .unzip(), syn::Fields::Unnamed(ref fields) => fields .unnamed .iter() .enumerate() - .map(|(i, f)| (&f.ty, syn::Ident::new(&i.to_string(), Span::call_site()))) + .map(|(i, f)| { + ( + &f.ty, + syn::Member::Unnamed(syn::Index { + index: i as u32, + span: Span::call_site(), + }), + ) + }) .unzip(), syn::Fields::Unit => (Vec::new(), Vec::new()), } } + +fn member_as_idents<'a>(members: &'a [syn::Member]) -> Vec> { + members + .iter() + .map(|member| match member { + syn::Member::Named(ident) => Cow::Borrowed(ident), + &syn::Member::Unnamed(syn::Index { index, span }) => { + Cow::Owned(syn::Ident::new(&format!("tuple_field_{}", index), span)) + } + }) + .collect() +} diff --git a/tests/derive.rs b/tests/derive.rs index 2ef4d626..c843459a 100644 --- a/tests/derive.rs +++ b/tests/derive.rs @@ -6,8 +6,13 @@ fn derive() { const TEST_DIR: &str = "tests/derive"; let t = trybuild::TestCases::new(); - let failures = &["enum.rs", "union.rs", "tuple_structs.rs"]; - let successes = &["unit_structs.rs", "named_structs.rs", "no_prelude.rs"]; + let failures = &["enum.rs", "union.rs"]; + let successes = &[ + "unit_structs.rs", + "tuple_structs.rs", + "named_structs.rs", + "no_prelude.rs", + ]; for &passing_test in successes { t.pass(&format!("{}/{}", TEST_DIR, passing_test)); } diff --git a/tests/derive/tuple_structs.stderr b/tests/derive/tuple_structs.stderr deleted file mode 100644 index 77a5522c..00000000 --- a/tests/derive/tuple_structs.stderr +++ /dev/null @@ -1,66 +0,0 @@ -thread 'rustc' panicked at '`"0"` is not a valid identifier', compiler\rustc_expand\src\proc_macro_server.rs:332:13 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc 1.48.0-nightly (154f1f544 2020-10-02) running on x86_64-pc-windows-msvc - -note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin - -note: some of the compiler flags provided by cargo are hidden - -error: proc-macro derive panicked - --> $DIR/tuple_structs.rs:3:10 - | -3 | #[derive(Bundle)] - | ^^^^^^ - | - = help: message: `"0"` is not a valid identifier - -thread 'rustc' panicked at '`"0"` is not a valid identifier', compiler\rustc_expand\src\proc_macro_server.rs:332:13 - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc 1.48.0-nightly (154f1f544 2020-10-02) running on x86_64-pc-windows-msvc - -note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin - -note: some of the compiler flags provided by cargo are hidden - -error: proc-macro derive panicked - --> $DIR/tuple_structs.rs:6:10 - | -6 | #[derive(Bundle)] - | ^^^^^^ - | - = help: message: `"0"` is not a valid identifier - -thread 'rustc' panicked at '`"0"` is not a valid identifier', compiler\rustc_expand\src\proc_macro_server.rs:332:13 - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc 1.48.0-nightly (154f1f544 2020-10-02) running on x86_64-pc-windows-msvc - -note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin - -note: some of the compiler flags provided by cargo are hidden - -error: proc-macro derive panicked - --> $DIR/tuple_structs.rs:9:10 - | -9 | #[derive(Bundle)] - | ^^^^^^ - | - = help: message: `"0"` is not a valid identifier