@@ -109,10 +109,8 @@ fn derive_for_enum(
109109 variants : & Punctuated < Variant , Comma > ,
110110) -> Result < TokenStream , syn:: Error > {
111111 let cardinality = enum_cardinality ( variants) ;
112- let first = init_enum ( ty, variants, Direction :: Forward ) ;
113- let last = init_enum ( ty, variants. iter ( ) . rev ( ) , Direction :: Backward ) ;
114112 let next_body = advance_enum ( ty, variants, Direction :: Forward ) ;
115- let previous_body = advance_enum ( ty, variants. iter ( ) . rev ( ) , Direction :: Backward ) ;
113+ let previous_body = advance_enum ( ty, variants, Direction :: Backward ) ;
116114 let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
117115 let where_clause = if generics. params . is_empty ( ) {
118116 where_clause. cloned ( )
@@ -129,6 +127,20 @@ fn derive_for_enum(
129127 ) ;
130128 Some ( clause)
131129 } ;
130+ let next_variant_body = next_variant ( ty, variants, Direction :: Forward ) ;
131+ let previous_variant_body = next_variant ( ty, variants, Direction :: Backward ) ;
132+ let ( first, last) = if variants. is_empty ( ) {
133+ (
134+ quote ! { :: core:: option:: Option :: None } ,
135+ quote ! { :: core:: option:: Option :: None } ,
136+ )
137+ } else {
138+ let last_index = variants. len ( ) - 1 ;
139+ (
140+ quote ! { next_variant( 0 ) } ,
141+ quote ! { previous_variant( #last_index) } ,
142+ )
143+ } ;
132144 let tokens = quote ! {
133145 impl #impl_generics :: enum_iterator:: Sequence for #ty #ty_generics #where_clause {
134146 #[ allow( clippy:: identity_op) ]
@@ -150,6 +162,21 @@ fn derive_for_enum(
150162 #last
151163 }
152164 }
165+
166+ fn next_variant #impl_generics(
167+ mut i: usize ,
168+ ) -> :: core:: option:: Option <#ty #ty_generics> #where_clause {
169+ #next_variant_body
170+ }
171+
172+ fn previous_variant #impl_generics(
173+ mut i: usize ,
174+ ) -> :: core:: option:: Option <#ty #ty_generics> #where_clause {
175+ #previous_variant_body
176+ }
177+ } ;
178+ let tokens = quote ! {
179+ const _: ( ) = { #tokens } ;
153180 } ;
154181 Ok ( tokens)
155182}
@@ -196,22 +223,40 @@ fn init_fields(fields: &Fields, direction: Direction) -> TokenStream {
196223 . collect :: < TokenStream > ( )
197224}
198225
199- fn init_enum < ' a , V > ( ty : & Ident , variants : V , direction : Direction ) -> TokenStream
200- where
201- V : IntoIterator < Item = & ' a Variant > ,
202- {
203- let inits = variants. into_iter ( ) . map ( |variant| {
204- let id = & variant. ident ;
205- let init = init_fields ( & variant. fields , direction) ;
226+ fn next_variant (
227+ ty : & Ident ,
228+ variants : & Punctuated < Variant , Comma > ,
229+ direction : Direction ,
230+ ) -> TokenStream {
231+ let advance = match direction {
232+ Direction :: Forward => {
233+ let last_index = variants. len ( ) . saturating_sub ( 1 ) ;
234+ quote ! {
235+ if i >= #last_index { break :: core:: option:: Option :: None ; } else { i+= 1 ; }
236+ }
237+ }
238+ Direction :: Backward => quote ! {
239+ if i == 0 { break :: core:: option:: Option :: None ; } else { i -= 1 ; }
240+ } ,
241+ } ;
242+ let arms = variants. iter ( ) . enumerate ( ) . map ( |( i, v) | {
243+ let id = & v. ident ;
244+ let init = init_fields ( & v. fields , direction) ;
206245 quote ! {
207- #ty:: #id { #init }
246+ #i => :: core :: option :: Option :: Some ( # ty:: #id { #init } )
208247 }
209248 } ) ;
210249 quote ! {
211- :: core:: option:: Option :: None
212- #(
213- . or_else( || :: core:: option:: Option :: Some ( #inits) )
214- ) *
250+ loop {
251+ let next = ( || match i {
252+ #( #arms, ) *
253+ _ => :: core:: option:: Option :: None ,
254+ } ) ( ) ;
255+ match next {
256+ :: core:: option:: Option :: Some ( _) => break next,
257+ :: core:: option:: Option :: None => #advance,
258+ }
259+ }
215260 }
216261}
217262
@@ -222,40 +267,60 @@ fn advance_struct(ty: &Ident, fields: &Fields, direction: Direction) -> TokenStr
222267 quote ! {
223268 let #ty { #assignments } = self ;
224269 let ( #( #bindings, ) * ) = #tuple?;
225- Some ( #ty { #assignments } )
270+ :: core :: option :: Option :: Some ( #ty { #assignments } )
226271 }
227272}
228273
229- fn advance_enum < ' a , V > ( ty : & Ident , variants : V , direction : Direction ) -> TokenStream
230- where
231- V : IntoIterator < Item = & ' a Variant > ,
232- V :: IntoIter : Clone ,
233- {
234- let mut variants = variants. into_iter ( ) ;
235- let arms = iter:: from_fn ( || variants. next ( ) . map ( |variant| ( variant, variants. clone ( ) ) ) ) . map (
236- |( variant, next_variants) | {
237- let next = init_enum ( ty, next_variants, direction) ;
238- let id = & variant. ident ;
239- let destructuring = field_bindings ( & variant. fields ) ;
240- let assignments = field_assignments ( & variant. fields ) ;
241- let bindings = bindings ( ) . take ( variant. fields . len ( ) ) . collect :: < Vec < _ > > ( ) ;
242- let tuple = advance_tuple ( & bindings, direction) ;
243- quote ! {
244- #ty:: #id { #destructuring } => {
245- #tuple
246- . map( |( #( #bindings, ) * ) | #ty:: #id { #assignments } )
247- . or_else( || #next)
248- }
249- }
250- } ,
251- ) ;
274+ fn advance_enum (
275+ ty : & Ident ,
276+ variants : & Punctuated < Variant , Comma > ,
277+ direction : Direction ,
278+ ) -> TokenStream {
279+ let arms: Vec < _ > = match direction {
280+ Direction :: Forward => variants
281+ . iter ( )
282+ . enumerate ( )
283+ . map ( |( i, variant) | advance_enum_arm ( ty, direction, i, variant) )
284+ . collect ( ) ,
285+ Direction :: Backward => variants
286+ . iter ( )
287+ . enumerate ( )
288+ . rev ( )
289+ . map ( |( i, variant) | advance_enum_arm ( ty, direction, i, variant) )
290+ . collect ( ) ,
291+ } ;
252292 quote ! {
253293 match * self {
254294 #( #arms, ) *
255295 }
256296 }
257297}
258298
299+ fn advance_enum_arm ( ty : & Ident , direction : Direction , i : usize , variant : & Variant ) -> TokenStream {
300+ let next = match direction {
301+ Direction :: Forward => match i. checked_add ( 1 ) {
302+ Some ( next_i) => quote ! { . or_else( || next_variant( #next_i) ) } ,
303+ None => quote ! { } ,
304+ } ,
305+ Direction :: Backward => match i. checked_sub ( 1 ) {
306+ Some ( prev_i) => quote ! { . or_else( || previous_variant( #prev_i) ) } ,
307+ None => quote ! { } ,
308+ } ,
309+ } ;
310+ let id = & variant. ident ;
311+ let destructuring = field_bindings ( & variant. fields ) ;
312+ let assignments = field_assignments ( & variant. fields ) ;
313+ let bindings = bindings ( ) . take ( variant. fields . len ( ) ) . collect :: < Vec < _ > > ( ) ;
314+ let tuple = advance_tuple ( & bindings, direction) ;
315+ quote ! {
316+ #ty:: #id { #destructuring } => {
317+ #tuple
318+ . map( |( #( #bindings, ) * ) | #ty:: #id { #assignments } )
319+ #next
320+ }
321+ }
322+ }
323+
259324fn advance_tuple ( bindings : & [ Ident ] , direction : Direction ) -> TokenStream {
260325 let advance = direction. advance ( ) ;
261326 let reset = direction. reset ( ) ;
@@ -287,7 +352,7 @@ fn advance_tuple(bindings: &[Ident], direction: Direction) -> TokenStream {
287352 ( :: core:: clone:: Clone :: clone( #rev_binding_tail) , false )
288353 } ;
289354 ) *
290- Some ( ( #( #bindings, ) * ) ) . filter( |_| !carry)
355+ :: core :: option :: Option :: Some ( ( #( #bindings, ) * ) ) . filter( |_| !carry)
291356 } ;
292357 quote ! {
293358 ( || { #body } ) ( )
0 commit comments