alloy_sol_macro_expander/
utils.rs

1use ast::Spanned;
2use proc_macro2::{Span, TokenStream};
3use quote::ToTokens;
4use tiny_keccak::{Hasher, Keccak};
5
6/// Simple interface to the [`keccak256`] hash function.
7///
8/// [`keccak256`]: https://en.wikipedia.org/wiki/SHA-3
9pub(crate) fn keccak256<T: AsRef<[u8]>>(bytes: T) -> [u8; 32] {
10    let mut output = [0u8; 32];
11    let mut hasher = Keccak::v256();
12    hasher.update(bytes.as_ref());
13    hasher.finalize(&mut output);
14    output
15}
16
17pub(crate) fn selector<T: AsRef<[u8]>>(bytes: T) -> ExprArray<u8> {
18    ExprArray::new(keccak256(bytes)[..4].to_vec())
19}
20
21pub(crate) fn event_selector<T: AsRef<[u8]>>(bytes: T) -> ExprArray<u8> {
22    ExprArray::new(keccak256(bytes).to_vec())
23}
24
25pub(crate) fn combine_errors(v: impl IntoIterator<Item = syn::Error>) -> syn::Result<()> {
26    match v.into_iter().reduce(|mut a, b| {
27        a.combine(b);
28        a
29    }) {
30        Some(e) => Err(e),
31        None => Ok(()),
32    }
33}
34
35#[derive(Clone, Debug)]
36pub(crate) struct ExprArray<T> {
37    pub(crate) array: Vec<T>,
38    pub(crate) span: Span,
39}
40
41impl<T: PartialOrd> PartialOrd for ExprArray<T> {
42    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43        self.array.partial_cmp(&other.array)
44    }
45}
46
47impl<T: Ord> Ord for ExprArray<T> {
48    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
49        self.array.cmp(&other.array)
50    }
51}
52
53impl<T: PartialEq> PartialEq for ExprArray<T> {
54    fn eq(&self, other: &Self) -> bool {
55        self.array == other.array
56    }
57}
58
59impl<T: Eq> Eq for ExprArray<T> {}
60
61impl<T> Spanned for ExprArray<T> {
62    fn span(&self) -> Span {
63        self.span
64    }
65
66    fn set_span(&mut self, span: Span) {
67        self.span = span;
68    }
69}
70
71impl<T> ExprArray<T> {
72    fn new(array: Vec<T>) -> Self {
73        Self { array, span: Span::call_site() }
74    }
75}
76
77impl<T: ToTokens> ToTokens for ExprArray<T> {
78    fn to_tokens(&self, tokens: &mut TokenStream) {
79        syn::token::Bracket(self.span).surround(tokens, |tokens| {
80            for t in &self.array {
81                t.to_tokens(tokens);
82                syn::token::Comma(self.span).to_tokens(tokens);
83            }
84        });
85    }
86}
87
88/// Applies [`proc_macro_error2`] programmatically.
89pub(crate) fn pme_compat(f: impl FnOnce() -> TokenStream) -> TokenStream {
90    pme_compat_result(|| Ok(f())).unwrap()
91}
92
93/// Applies [`proc_macro_error2`] programmatically.
94pub(crate) fn pme_compat_result(
95    f: impl FnOnce() -> syn::Result<TokenStream>,
96) -> syn::Result<TokenStream> {
97    let mut r = None;
98    let e = proc_macro_error2::entry_point(
99        std::panic::AssertUnwindSafe(|| {
100            r = Some(f());
101            Default::default()
102        }),
103        false,
104    );
105    if let Some(r) = r {
106        if e.is_empty() || r.is_err() {
107            return r;
108        }
109    }
110    Ok(e.into())
111}