const_array_attrs/
sorted.rs

1use proc_macro2::TokenStream;
2use syn:: {
3    ItemConst,
4    Expr, ExprArray,
5    Lit,
6    parse:: { self, Parse, ParseStream },
7};
8use quote:: { quote, ToTokens };
9
10pub struct SortedTable(ItemConst);
11
12impl Parse for SortedTable {
13    fn parse(input: ParseStream) -> parse::Result<Self> {
14        let mut item_const: ItemConst = input.parse()?;
15
16        match item_const.expr.as_mut() {
17            Expr::Array(ExprArray {
18                ref mut elems, ..
19            }) => {
20                let mut new_elems: Vec<Expr> = Vec::new();
21
22                while let Some(ex) = elems.pop() {
23                    if let Err(i) = new_elems.binary_search_by(
24                        |p| get_key(p).cmp(&get_key(ex.value()))
25                    ) {
26                        new_elems.insert(i, ex.into_value());
27                    }
28                }
29                for ex in new_elems {
30                    elems.push(ex);
31                }
32            },
33            _ => (),
34        }
35        Ok(Self(item_const))
36    }
37}
38
39impl ToTokens for SortedTable {
40    fn to_tokens(&self, tokens: &mut TokenStream) {
41        let item_const = &self.0;
42
43        tokens.extend(quote! { #item_const });
44    }
45}
46
47fn get_key(ex: &Expr) -> String {
48    use Expr::*;
49
50    match ex {
51        Tuple(tuple) => match tuple.elems.first() {
52            Some(Lit(expr)) => lit_to_string(&expr.lit),
53            _ => panic!(),
54        },
55        Lit(expr) => lit_to_string(&expr.lit),
56        _ => panic!(),
57    }
58}
59
60fn lit_to_string(lit: &Lit) -> String {
61    use Lit::*;
62    match lit {
63        Str(s) => s.value(),
64        ByteStr(s) => String::from_utf8(s.value()).unwrap(),
65        Byte(s) => s.value().to_string(),
66        Char(s) => s.value().into(),
67        Int(s) => s.base10_parse().unwrap(),
68        Float(s) => s.base10_parse().unwrap(),
69        Bool(s) => s.value().to_string(),
70        Verbatim(s) => s.to_string(),
71    }
72}