code_hasher/lib.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7//! 
8//! [](https://github.com/dusk-network/code-hasher)
9//! [](https://docs.rs/code-hasher/)
10//! # code-hasher
11//!
12//! Tiny proc macro library designed to hash a code block generating a unique
13//! identifier for it which will get written into a `const` inside of the code
14//! block.
15//!
16//! ## Example
17//! ```rust
18//! #[code_hasher::hash(SOME_CONST_NAME, version = "0.1.0")]
19//! pub mod testing_module {
20//!
21//! pub fn this_does_something() -> [u8; 32] {
22//! SOME_CONST_NAME
23//! }
24//! }
25//! ```
26//!
27//! Here, `SOME_CONST_NAME` has assigned as value the resulting hash of:
28//! - The code contained inside `testing_module`.
29//! - The version passed by the user (is optional). Not adding it will basically
30//! not hash this attribute and **WILL NOT** use any default alternatives.
31//!
32//! ## Licensing
33//! This code is licensed under Mozilla Public License Version 2.0 (MPL-2.0).
34//! Please see [LICENSE](https://github.com/dusk-network/rusk/tree/master/macros/code-hasher/LICENSE) for further info.
35
36use blake3::Hasher;
37use proc_macro::TokenStream;
38
39#[proc_macro_attribute]
40pub fn hash(attr: TokenStream, input: TokenStream) -> TokenStream {
41 let mut hasher = Hasher::new();
42
43 // We need to `let` this otherways it gets freed while borrowed.
44 let attrs_string = format!("{}", attr.to_string());
45 let attrs_split: Vec<&str> = attrs_string.split(",").collect();
46
47 // Add the code version (passed as attribute) to the hasher.
48 hasher.update(attrs_split.get(1).unwrap_or(&"").as_bytes());
49 // Add code-block to the hasher.
50 hasher.update(input.to_string().as_bytes());
51
52 let id = hasher.finalize().as_bytes().clone();
53 let mut token_stream = format!("{}", input.to_string());
54 token_stream.pop();
55 token_stream.push_str(&format!(
56 " const {}: [u8; 32] = {:?};",
57 attrs_split.get(0).expect("Missing const name"),
58 id
59 ));
60 token_stream.push_str(" }");
61 token_stream.parse().expect(
62 "Error parsing the output of the code-hasher macro as TokenStream",
63 )
64}