1
1
use proc_macro2:: TokenStream ;
2
2
use quote:: { format_ident, quote, ToTokens } ;
3
- use syn:: { parse :: Nothing , Field , Fields , FieldsNamed , FieldsUnnamed , ItemEnum , Result , Variant } ;
3
+ use syn:: { Field , Fields , FieldsNamed , FieldsUnnamed , ItemEnum , Result , Variant } ;
4
4
5
- use crate :: utils:: VecExt ;
5
+ use crate :: utils:: collect_cfg ;
6
6
7
- use super :: { Context , PIN } ;
7
+ use super :: Context ;
8
8
9
9
pub ( super ) fn parse ( cx : & mut Context , mut item : ItemEnum ) -> Result < TokenStream > {
10
10
if item. variants . is_empty ( ) {
11
- return Err ( error ! (
12
- item,
13
- "#[pin_project] attribute may not be used on enums without variants"
11
+ return Err ( syn :: Error :: new (
12
+ item. brace_token . span ,
13
+ "#[pin_project] attribute may not be used on enums without variants" ,
14
14
) ) ;
15
15
}
16
16
let has_field = item. variants . iter ( ) . try_fold ( false , |has_field, v| {
@@ -62,17 +62,22 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemEnum) -> Result<TokenStream>
62
62
fn variants ( cx : & mut Context , item : & mut ItemEnum ) -> Result < ( Vec < TokenStream > , Vec < TokenStream > ) > {
63
63
let mut proj_variants = Vec :: with_capacity ( item. variants . len ( ) ) ;
64
64
let mut proj_arms = Vec :: with_capacity ( item. variants . len ( ) ) ;
65
- for Variant { fields, ident, .. } in & mut item. variants {
65
+ for Variant { attrs , fields, ident, .. } in & mut item. variants {
66
66
let ( proj_pat, proj_body, proj_fields) = match fields {
67
67
Fields :: Unnamed ( fields) => unnamed ( cx, fields) ?,
68
68
Fields :: Named ( fields) => named ( cx, fields) ?,
69
69
Fields :: Unit => ( TokenStream :: new ( ) , TokenStream :: new ( ) , TokenStream :: new ( ) ) ,
70
70
} ;
71
+ let cfg = collect_cfg ( attrs) ;
71
72
let Context { orig_ident, proj_ident, .. } = & cx;
72
- let proj_arm = quote ! ( #orig_ident:: #ident #proj_pat => #proj_ident:: #ident #proj_body ) ;
73
- let proj_variant = quote ! ( #ident #proj_fields) ;
74
- proj_arms. push ( proj_arm) ;
75
- proj_variants. push ( proj_variant) ;
73
+ proj_variants. push ( quote ! {
74
+ #( #cfg) * #ident #proj_fields
75
+ } ) ;
76
+ proj_arms. push ( quote ! {
77
+ #( #cfg) * #orig_ident:: #ident #proj_pat => {
78
+ #proj_ident:: #ident #proj_body
79
+ }
80
+ } ) ;
76
81
}
77
82
78
83
Ok ( ( proj_variants, proj_arms) )
@@ -86,18 +91,27 @@ fn named(
86
91
let mut proj_body = Vec :: with_capacity ( fields. len ( ) ) ;
87
92
let mut proj_fields = Vec :: with_capacity ( fields. len ( ) ) ;
88
93
for Field { attrs, ident, ty, .. } in fields {
89
- if let Some ( attr) = attrs. find_remove ( PIN ) {
90
- let _: Nothing = syn:: parse2 ( attr. tokens ) ?;
91
- cx. push_unpin_bounds ( ty. clone ( ) ) ;
94
+ let cfg = collect_cfg ( attrs) ;
95
+ if cx. find_pin_attr ( attrs) ? {
92
96
let lifetime = & cx. lifetime ;
93
- proj_fields. push ( quote ! ( #ident: :: core:: pin:: Pin <& #lifetime mut #ty>) ) ;
94
- proj_body. push ( quote ! ( #ident: :: core:: pin:: Pin :: new_unchecked( #ident) ) ) ;
97
+ proj_fields. push ( quote ! {
98
+ #( #cfg) * #ident: :: core:: pin:: Pin <& #lifetime mut #ty>
99
+ } ) ;
100
+ proj_body. push ( quote ! {
101
+ #( #cfg) * #ident: :: core:: pin:: Pin :: new_unchecked( #ident)
102
+ } ) ;
95
103
} else {
96
104
let lifetime = & cx. lifetime ;
97
- proj_fields. push ( quote ! ( #ident: & #lifetime mut #ty) ) ;
98
- proj_body. push ( quote ! ( #ident) ) ;
105
+ proj_fields. push ( quote ! {
106
+ #( #cfg) * #ident: & #lifetime mut #ty
107
+ } ) ;
108
+ proj_body. push ( quote ! {
109
+ #( #cfg) * #ident: #ident
110
+ } ) ;
99
111
}
100
- proj_pat. push ( ident) ;
112
+ proj_pat. push ( quote ! {
113
+ #( #cfg) * #ident
114
+ } ) ;
101
115
}
102
116
103
117
let proj_pat = quote ! ( { #( #proj_pat) , * } ) ;
@@ -114,19 +128,34 @@ fn unnamed(
114
128
let mut proj_body = Vec :: with_capacity ( fields. len ( ) ) ;
115
129
let mut proj_fields = Vec :: with_capacity ( fields. len ( ) ) ;
116
130
for ( i, Field { attrs, ty, .. } ) in fields. iter_mut ( ) . enumerate ( ) {
117
- let x = format_ident ! ( "_x{}" , i) ;
118
- if let Some ( attr) = attrs. find_remove ( PIN ) {
119
- let _: Nothing = syn:: parse2 ( attr. tokens ) ?;
120
- cx. push_unpin_bounds ( ty. clone ( ) ) ;
131
+ let id = format_ident ! ( "_x{}" , i) ;
132
+ let cfg = collect_cfg ( attrs) ;
133
+ if !cfg. is_empty ( ) {
134
+ return Err ( error ! (
135
+ cfg. first( ) ,
136
+ "`cfg` attributes on the field of tuple variants are not supported"
137
+ ) ) ;
138
+ }
139
+ if cx. find_pin_attr ( attrs) ? {
121
140
let lifetime = & cx. lifetime ;
122
- proj_fields. push ( quote ! ( :: core:: pin:: Pin <& #lifetime mut #ty>) ) ;
123
- proj_body. push ( quote ! ( :: core:: pin:: Pin :: new_unchecked( #x) ) ) ;
141
+ proj_fields. push ( quote ! {
142
+ :: core:: pin:: Pin <& #lifetime mut #ty>
143
+ } ) ;
144
+ proj_body. push ( quote ! {
145
+ :: core:: pin:: Pin :: new_unchecked( #id)
146
+ } ) ;
124
147
} else {
125
148
let lifetime = & cx. lifetime ;
126
- proj_fields. push ( quote ! ( & #lifetime mut #ty) ) ;
127
- proj_body. push ( quote ! ( #x) ) ;
149
+ proj_fields. push ( quote ! {
150
+ & #lifetime mut #ty
151
+ } ) ;
152
+ proj_body. push ( quote ! {
153
+ #id
154
+ } ) ;
128
155
}
129
- proj_pat. push ( x) ;
156
+ proj_pat. push ( quote ! {
157
+ #id
158
+ } ) ;
130
159
}
131
160
132
161
let proj_pat = quote ! ( ( #( #proj_pat) , * ) ) ;
0 commit comments