1extern crate proc_macro;
2use proc_macro::TokenStream;
3
4use std::collections::HashMap;
5
6use once_cell::sync::OnceCell;
7use quote::quote;
8use syn::parse::{Parse, ParseStream};
9use syn::parse_macro_input;
10
11use crcany_core::spec::Spec;
12
13struct CrcInput {
15 name: syn::LitStr,
16}
17
18impl Parse for CrcInput {
19 fn parse(input: ParseStream) -> syn::Result<Self> {
20 let name = input.parse()?;
21 Ok(CrcInput { name })
22 }
23}
24
25const ALL_CRCS_STR: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/allcrcs-abbrev.txt"));
26
27fn all_crcs() -> &'static HashMap<String, Spec> {
28 static ALL_CRCS: OnceCell<HashMap<String, Spec>> = OnceCell::new();
29 ALL_CRCS.get_or_init(|| {
30 let all_specs = ALL_CRCS_STR
31 .lines()
32 .map(|line| line.parse())
33 .collect::<Result<Vec<Spec>, _>>()
34 .unwrap_or_default();
35
36 all_specs
37 .into_iter()
38 .map(|spec| (spec.name.clone(), spec))
39 .collect::<HashMap<String, Spec>>()
40 })
41}
42
43fn get_crc(name: &str) -> Option<&'static Spec> {
45 let map = all_crcs();
46 map.get(name)
47}
48
49#[proc_macro]
65pub fn impl_crc(input: TokenStream) -> TokenStream {
66 let input = parse_macro_input!(input as CrcInput);
67 let name = input.name.value();
68
69 let tokens = if let Some(spec) = get_crc(&name) {
70 crcany_core::gen::gen_mod(spec)
71 } else {
72 panic!("Unable to find CRC named {}!", name);
73 };
74
75 tokens.into()
76}
77
78#[proc_macro]
79pub fn impl_all(_input: TokenStream) -> TokenStream {
80 let mut tokens = quote!();
81
82 for name in all_crcs().keys() {
83 tokens = quote!(#tokens ::crcany::impl_crc!(#name););
84 }
85
86 tokens.into()
87}