stable_step_derive/
lib.rs1use proc_macro::{self, TokenStream};
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput};
4
5#[proc_macro_derive(Step)]
6pub fn derive(input: TokenStream) -> TokenStream {
7 let DeriveInput {
8 ident,
9 generics,
10 data,
11 ..
12 } = parse_macro_input!(input);
13
14 let data = if let Data::Enum(data) = data {
15 data
16 } else {
17 panic!("Step can only be derived for Enums");
18 };
19
20 for variant in &data.variants {
21 if !variant.fields.is_empty() {
22 panic!("Step can only be derived for Enums with no variant fields");
23 }
24 }
25
26 if data.variants.is_empty() {
27 panic!("Step cannot be derived for an empty Enum");
28 }
29
30 let first = data.variants.iter().next().unwrap();
31 let last = data.variants.iter().last().unwrap();
32
33 let nexts: proc_macro2::TokenStream = data
34 .variants
35 .iter()
36 .zip(data.variants.iter().skip(1))
37 .map(|(lesser, greater)| {
38 let lesser = &lesser.ident;
39 let greater = &greater.ident;
40 quote! {
41 Self::#lesser => Some(Self::#greater),
42 }
43 })
44 .collect();
45
46 let prevs: proc_macro2::TokenStream = data
47 .variants
48 .iter()
49 .zip(data.variants.iter().skip(1))
50 .map(|(lesser, greater)| {
51 let lesser = &lesser.ident;
52 let greater = &greater.ident;
53 quote! {
54 Self::#greater => Some(Self::#lesser),
55 }
56 })
57 .collect();
58
59 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
60
61 let output = quote! {
62 impl #impl_generics ::stable_step::Step for #ident #type_generics #where_clause {
63 const MIN: Self = Self::#first;
64 const MAX: Self = Self::#last;
65
66 fn next(&self) -> Option<Self>
67 where
68 Self: Sized,
69 {
70 match self {
71 Self::#last => None,
72 #nexts
73 }
74 }
75
76 fn prev(&self) -> Option<Self>
77 where
78 Self: Sized,
79 {
80 match self {
81 Self::#first => None,
82 #prevs
83 }
84 }
85 }
86 };
87
88 output.into()
89}