Skip to main content

ps_hash_macros/
lib.rs

1mod expand;
2mod input;
3
4use proc_macro::TokenStream;
5use syn::parse_macro_input;
6
7fn expand_hash_expr(expr: &syn::Expr) -> proc_macro2::TokenStream {
8    match expand::expand_hash(expr) {
9        Ok(tokens) => tokens,
10        Err(error) => error.to_compile_error(),
11    }
12}
13
14/// Hashes literal input at compile time and expands to the canonical
15/// Crockford Base32 form as a `&'static str`.
16///
17/// Accepts a string literal, byte string literal, byte array literal, or
18/// byte repeat expression. The expansion equals the runtime
19/// `ps_hash::hash(input)?.to_string()` for the same input. Any other input
20/// produces a compile error.
21///
22/// # Examples
23///
24/// ```
25/// const HASH: &str = ps_hash_macros::hash!("hello");
26///
27/// assert_eq!(HASH.len(), 77);
28/// assert_eq!(HASH, ps_hash_macros::hash!(b"hello"));
29/// assert_eq!(HASH, ps_hash_macros::hash!([b'h', b'e', b'l', b'l', b'o']));
30/// ```
31#[proc_macro]
32pub fn hash(input: TokenStream) -> TokenStream {
33    let expr = parse_macro_input!(input as syn::Expr);
34    expand_hash_expr(&expr).into()
35}
36
37#[cfg(test)]
38#[allow(clippy::expect_used)]
39mod tests {
40    use syn::parse_quote;
41
42    use super::expand_hash_expr;
43
44    #[test]
45    fn dispatcher_expands_hash_macro_input() {
46        let output = expand_hash_expr(&parse_quote!("dispatcher"));
47        let literal: syn::LitStr = syn::parse2(output).expect("output should be a string literal");
48
49        let expected =
50            ps_hash_core::hash_encoded(b"dispatcher").expect("hash_encoded should succeed");
51        let expected = String::from_utf8_lossy(&expected).into_owned();
52
53        assert_eq!(literal.value(), expected);
54    }
55}