const-array-attrs 0.0.3

Attribute macros for const array.
Documentation
use proc_macro2::TokenStream;
use syn:: {
    ItemConst,
    Expr, ExprArray,
    Lit,
    parse:: { self, Parse, ParseStream },
};
use quote:: { quote, ToTokens };

pub struct SortedTable(ItemConst);

impl Parse for SortedTable {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        let mut item_const: ItemConst = input.parse()?;

        match item_const.expr.as_mut() {
            Expr::Array(ExprArray {
                ref mut elems, ..
            }) => {
                let mut new_elems: Vec<Expr> = Vec::new();

                while let Some(ex) = elems.pop() {
                    if let Err(i) = new_elems.binary_search_by(
                        |p| get_key(p).cmp(&get_key(ex.value()))
                    ) {
                        new_elems.insert(i, ex.into_value());
                    }
                }
                for ex in new_elems {
                    elems.push(ex);
                }
            },
            _ => (),
        }
        Ok(Self(item_const))
    }
}

impl ToTokens for SortedTable {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let item_const = &self.0;

        tokens.extend(quote! { #item_const });
    }
}

fn get_key(ex: &Expr) -> String {
    use Expr::*;

    match ex {
        Tuple(tuple) => match tuple.elems.first() {
            Some(Lit(expr)) => lit_to_string(&expr.lit),
            _ => panic!(),
        },
        Lit(expr) => lit_to_string(&expr.lit),
        _ => panic!(),
    }
}

fn lit_to_string(lit: &Lit) -> String {
    use Lit::*;
    match lit {
        Str(s) => s.value(),
        ByteStr(s) => String::from_utf8(s.value()).unwrap(),
        Byte(s) => s.value().to_string(),
        Char(s) => s.value().into(),
        Int(s) => s.base10_parse().unwrap(),
        Float(s) => s.base10_parse().unwrap(),
        Bool(s) => s.value().to_string(),
        Verbatim(s) => s.to_string(),
    }
}