diff --git a/src/lib.rs b/src/lib.rs index a2de8c6..a5a6126 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,13 +292,44 @@ impl BodyGenerator for BorrowedGen { } fn visit_struct(&self, data: &syn::DataStruct) -> proc_macro2::TokenStream { - let fields = data.fields.iter().map(|field| { - let ident = field.ident.as_ref().expect("this fields has no ident (4)"); - let field_ref = quote! { self.#ident }; - let code = FieldKind::resolve(&field.ty).borrow_or_clone(&field_ref); - quote! { #ident: #code } - }); - quote! { { #(#fields),* } } + // Helper ternary to avoid Option + enum Fields { + Named, + Tuple, + Unit, + } + + use Fields::*; + + let fields_kind = data + .fields + .iter() + .next() + .map(|field| if field.ident.is_some() { Named } else { Tuple }) + .unwrap_or(Unit); + + match fields_kind { + Named => { + let fields = data.fields.iter().map(|field| { + let ident = field.ident.as_ref().expect("unexpected unnamed field"); + let field_ref = quote! { self.#ident }; + let code = FieldKind::resolve(&field.ty).borrow_or_clone(&field_ref); + quote! { #ident: #code } + }); + quote! { { #(#fields),* } } + } + Tuple => { + let fields = data.fields.iter().enumerate().map(|(index, field)| { + let index = syn::Index::from(index); + let index = quote! { self.#index }; + FieldKind::resolve(&field.ty).borrow_or_clone(&index) + }); + quote! { ( #(#fields),* ) } + } + Unit => { + quote! {} + } + } } fn visit_enum_data( diff --git a/tests/tuple_struct.rs b/tests/tuple_struct.rs index 05e7467..a95b73b 100644 --- a/tests/tuple_struct.rs +++ b/tests/tuple_struct.rs @@ -3,22 +3,21 @@ #[macro_use] extern crate derive_into_owned; -use std::borrow; -use std::borrow::Cow; +use std::borrow::{self, Cow}; -#[derive(IntoOwned)] +#[derive(IntoOwned, Borrowed)] struct Foo<'a>(Cow<'a, str>); -#[derive(IntoOwned)] +#[derive(IntoOwned, Borrowed)] struct FooExtraFields<'a>(u32, Cow<'a, str>, bool, Vec); -#[derive(IntoOwned)] +#[derive(IntoOwned, Borrowed)] struct Bar<'a>(::std::borrow::Cow<'a, str>); -#[derive(IntoOwned)] +#[derive(IntoOwned, Borrowed)] struct Car<'a>(std::borrow::Cow<'a, str>); -#[derive(IntoOwned)] +#[derive(IntoOwned, Borrowed)] struct Dar<'a>(borrow::Cow<'a, str>); #[test] @@ -26,10 +25,19 @@ fn tuple_struct() { let non_static_string: String = "foobar".to_string(); let thing = Foo(Cow::Borrowed(&non_static_string)); + let owned = thing.into_owned(); - accepts_only_static(thing.into_owned()); + accepts_only_static(&owned); + + let borrowed = owned.borrowed(); + // owned cannot be moved while borrowed exists + test_borrowed(&owned, borrowed); } -fn accepts_only_static(static_foo: Foo<'static>) { - drop(static_foo); +fn accepts_only_static(_static_foo: &Foo<'static>) {} + +fn test_borrowed<'b, 'a: 'b>(lives_longer: &Foo<'a>, lives_less: Foo<'b>) { + drop(lives_less); + #[allow(dropping_references)] + drop(lives_longer); }