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//! ![Build Status](https://github.com/dusk-network/rusk/workflows/Continuous%20integration/badge.svg)
8//! [![Repository](https://img.shields.io/badge/github-code--hasher-blueviolet?logo=github)](https://github.com/dusk-network/code-hasher)
9//! [![Documentation](https://img.shields.io/badge/docs-code--hasher-blue?logo=rust)](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}