Skip to content

Commit 5f65417

Browse files
committed
fix: Allow deriving Borrowed for unit and tuple structs
This just copies the logic for handling tuple and unit structs from IntoOwnedGen to BorrowedGen.
1 parent 38208b2 commit 5f65417

File tree

2 files changed

+56
-17
lines changed

2 files changed

+56
-17
lines changed

src/lib.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,44 @@ impl BodyGenerator for BorrowedGen {
292292
}
293293

294294
fn visit_struct(&self, data: &syn::DataStruct) -> proc_macro2::TokenStream {
295-
let fields = data.fields.iter().map(|field| {
296-
let ident = field.ident.as_ref().expect("this fields has no ident (4)");
297-
let field_ref = quote! { self.#ident };
298-
let code = FieldKind::resolve(&field.ty).borrow_or_clone(&field_ref);
299-
quote! { #ident: #code }
300-
});
301-
quote! { { #(#fields),* } }
295+
// Helper ternary to avoid Option<bool>
296+
enum Fields {
297+
Named,
298+
Tuple,
299+
Unit,
300+
}
301+
302+
use Fields::*;
303+
304+
let fields_kind = data
305+
.fields
306+
.iter()
307+
.next()
308+
.map(|field| if field.ident.is_some() { Named } else { Tuple })
309+
.unwrap_or(Unit);
310+
311+
match fields_kind {
312+
Named => {
313+
let fields = data.fields.iter().map(|field| {
314+
let ident = field.ident.as_ref().expect("unexpected unnamed field");
315+
let field_ref = quote! { self.#ident };
316+
let code = FieldKind::resolve(&field.ty).borrow_or_clone(&field_ref);
317+
quote! { #ident: #code }
318+
});
319+
quote! { { #(#fields),* } }
320+
}
321+
Tuple => {
322+
let fields = data.fields.iter().enumerate().map(|(index, field)| {
323+
let index = syn::Index::from(index);
324+
let index = quote! { self.#index };
325+
FieldKind::resolve(&field.ty).borrow_or_clone(&index)
326+
});
327+
quote! { ( #(#fields),* ) }
328+
}
329+
Unit => {
330+
quote! {}
331+
}
332+
}
302333
}
303334

304335
fn visit_enum_data(

tests/tuple_struct.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,41 @@
33
#[macro_use]
44
extern crate derive_into_owned;
55

6-
use std::borrow;
7-
use std::borrow::Cow;
6+
use std::borrow::{self, Cow};
87

9-
#[derive(IntoOwned)]
8+
#[derive(IntoOwned, Borrowed)]
109
struct Foo<'a>(Cow<'a, str>);
1110

12-
#[derive(IntoOwned)]
11+
#[derive(IntoOwned, Borrowed)]
1312
struct FooExtraFields<'a>(u32, Cow<'a, str>, bool, Vec<bool>);
1413

15-
#[derive(IntoOwned)]
14+
#[derive(IntoOwned, Borrowed)]
1615
struct Bar<'a>(::std::borrow::Cow<'a, str>);
1716

18-
#[derive(IntoOwned)]
17+
#[derive(IntoOwned, Borrowed)]
1918
struct Car<'a>(std::borrow::Cow<'a, str>);
2019

21-
#[derive(IntoOwned)]
20+
#[derive(IntoOwned, Borrowed)]
2221
struct Dar<'a>(borrow::Cow<'a, str>);
2322

2423
#[test]
2524
fn tuple_struct() {
2625
let non_static_string: String = "foobar".to_string();
2726

2827
let thing = Foo(Cow::Borrowed(&non_static_string));
28+
let owned = thing.into_owned();
2929

30-
accepts_only_static(thing.into_owned());
30+
accepts_only_static(&owned);
31+
32+
let borrowed = owned.borrowed();
33+
// owned cannot be moved while borrowed exists
34+
test_borrowed(&owned, borrowed);
3135
}
3236

33-
fn accepts_only_static(static_foo: Foo<'static>) {
34-
drop(static_foo);
37+
fn accepts_only_static(_static_foo: &Foo<'static>) {}
38+
39+
fn test_borrowed<'b, 'a: 'b>(lives_longer: &Foo<'a>, lives_less: Foo<'b>) {
40+
drop(lives_less);
41+
#[allow(dropping_references)]
42+
drop(lives_longer);
3543
}

0 commit comments

Comments
 (0)