|
1 |
| -use proc_macro2::TokenStream; |
| 1 | +use proc_macro2::{Ident, TokenStream}; |
2 | 2 | use quote::quote;
|
3 | 3 | use syn::{Item, parse_macro_input};
|
4 | 4 | use syn::spanned::Spanned;
|
5 | 5 |
|
6 |
| -fn check(args: TokenStream, input: Item) -> TokenStream{ |
| 6 | +fn check_enum_order(args: &TokenStream, input: &Item) -> syn::Result<()>{ |
| 7 | + let mut idents = vec![]; |
7 | 8 | match input{
|
8 | 9 | Item::Enum(ref item) =>{
|
9 |
| - let mut names: Vec<String> = vec![]; |
10 | 10 | for variant in item.variants.iter() {
|
11 |
| - let cur_name = variant.ident.to_string(); |
12 |
| - for name in names.iter() { |
13 |
| - if &cur_name < name{ |
14 |
| - let msg = format!("{} should sort before {}", cur_name, name); |
15 |
| - return syn::Error::new(variant.span(), msg).into_compile_error(); |
16 |
| - } |
17 |
| - } |
18 |
| - names.push(cur_name); |
| 11 | + idents.push(&variant.ident); |
19 | 12 | }
|
20 |
| - return quote! { #input } |
| 13 | + check_order(idents) |
21 | 14 | },
|
22 | 15 | _=>{
|
23 |
| - return syn::Error::new(args.span(), "expected enum or match expression").into_compile_error(); |
| 16 | + Err(syn::Error::new(args.span(), "expected enum or match expression")) |
24 | 17 | }
|
25 | 18 | }
|
26 | 19 | }
|
27 | 20 |
|
| 21 | +fn check_order(idents: Vec<&Ident>)-> syn::Result<()> { |
| 22 | + if idents.is_empty(){ |
| 23 | + return Ok(()); |
| 24 | + } |
| 25 | + let mut sorted = idents.clone(); |
| 26 | + sorted.sort_by(|ident1, ident2| ident1.cmp(ident2)); |
| 27 | + for (a, b) in idents.iter().zip(sorted.iter()) { |
| 28 | + if a.to_string() != b.to_string(){ |
| 29 | + let msg = format!("{} should sort before {}", b.to_string(), a.to_string()); |
| 30 | + return Err(syn::Error::new(b.span(), msg)); |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + Ok(()) |
| 35 | +} |
| 36 | + |
28 | 37 |
|
29 | 38 | #[proc_macro_attribute]
|
30 | 39 | pub fn sorted(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
31 | 40 | let input = parse_macro_input!(input as Item);
|
32 | 41 | let args: TokenStream = args.into();
|
33 |
| - check(args.into(), input).into() |
| 42 | + let mut result = TokenStream::new(); |
| 43 | + match check_enum_order(&args, &input) { |
| 44 | + Ok(_) =>{}, |
| 45 | + Err(err) => { |
| 46 | + result.extend(err.into_compile_error()); |
| 47 | + } |
| 48 | + } |
| 49 | + result.extend(quote! { #input }); |
| 50 | + result.into() |
34 | 51 | }
|
35 | 52 |
|
36 | 53 |
|
0 commit comments