crcany_macro/
lib.rs

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
13// TODO: explicit params?
14struct 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
43// TODO: search maybe?
44fn get_crc(name: &str) -> Option<&'static Spec> {
45    let map = all_crcs();
46    map.get(name)
47}
48
49/// Implement a module to calculate a CRC.
50///
51/// The string parameter must match exactly the name of one of
52/// the sets of CRC parameters.
53///
54/// ```
55/// use crcany::crc::v2::Crc;
56/// use crcany::impl_crc;
57///
58/// impl_crc!("CRC-3/GSM");
59///
60/// let mut crc = crc3gsm::bitwise::Crc3Gsm::new();
61/// crc.add_bytes(b"123456789");
62/// assert_eq!(4, crc.to_inner());
63/// ```
64#[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}