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(),
}
}