alloy_sol_macro_expander/
verbatim.rs

1use crate::expand::ExternCrates;
2use proc_macro2::TokenStream;
3use quote::quote;
4use std::collections::BTreeMap;
5
6/// Converts the given value into tokens that represent itself.
7pub(crate) fn verbatim<T: Verbatim>(t: &T, crates: &ExternCrates) -> TokenStream {
8    let mut s = TokenStream::new();
9    t.to_verbatim_tokens(&mut s, crates);
10    s
11}
12
13/// Conversion to tokens that represent the value itself.
14pub(crate) trait Verbatim {
15    /// Converts `self` into tokens that represent itself.
16    fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates);
17}
18
19/// Provides a [`quote::ToTokens`] implementations for references of values that implement
20/// [`Verbatim`].
21pub(crate) struct ToTokensCompat<'a, T: ?Sized + Verbatim>(pub(crate) &'a T, &'a ExternCrates);
22
23impl<T: Verbatim> quote::ToTokens for ToTokensCompat<'_, T> {
24    #[inline]
25    fn to_tokens(&self, tokens: &mut TokenStream) {
26        self.0.to_verbatim_tokens(tokens, self.1)
27    }
28}
29
30impl Verbatim for String {
31    fn to_verbatim_tokens(&self, tokens: &mut TokenStream, crates: &ExternCrates) {
32        let alloy_sol_types = &crates.sol_types;
33        tokens.extend(if self.is_empty() {
34            quote!(#alloy_sol_types::private::String::new())
35        } else {
36            quote!(#alloy_sol_types::private::ToOwned::to_owned(#self))
37        })
38    }
39}
40
41impl Verbatim for bool {
42    #[inline]
43    fn to_verbatim_tokens(&self, s: &mut TokenStream, _crates: &ExternCrates) {
44        quote::ToTokens::to_tokens(self, s)
45    }
46}
47
48impl Verbatim for usize {
49    #[inline]
50    fn to_verbatim_tokens(&self, s: &mut TokenStream, _crates: &ExternCrates) {
51        quote::ToTokens::to_tokens(self, s)
52    }
53}
54
55impl<T: Verbatim> Verbatim for Vec<T> {
56    fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates) {
57        let alloy_sol_types = &crates.sol_types;
58        s.extend(if self.is_empty() {
59            quote!(#alloy_sol_types::private::Vec::new())
60        } else {
61            let iter = self.iter().map(|t| ToTokensCompat(t, crates));
62            quote!(#alloy_sol_types::private::vec![#(#iter),*])
63        });
64    }
65}
66
67impl<K: Verbatim, V: Verbatim> Verbatim for BTreeMap<K, V> {
68    fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates) {
69        let alloy_sol_types = &crates.sol_types;
70        s.extend(if self.is_empty() {
71            quote!(#alloy_sol_types::private::BTreeMap::new())
72        } else {
73            let k = self.keys().map(|t| ToTokensCompat(t, crates));
74            let v = self.values().map(|t| ToTokensCompat(t, crates));
75            quote!(#alloy_sol_types::private::BTreeMap::from([#( (#k, #v) ),*]))
76        });
77    }
78}
79
80impl<T: Verbatim> Verbatim for Option<T> {
81    fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates) {
82        let tts = match self {
83            Some(t) => {
84                let mut s = TokenStream::new();
85                t.to_verbatim_tokens(&mut s, crates);
86                quote!(::core::option::Option::Some(#s))
87            }
88            None => quote!(::core::option::Option::None),
89        };
90        s.extend(tts);
91    }
92}
93
94macro_rules! derive_verbatim {
95    () => {};
96
97    (struct $name:ident { $($field:ident),* $(,)? } $($rest:tt)*) => {
98        impl Verbatim for alloy_json_abi::$name {
99            fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates) {
100                let Self { $($field),* } = self;
101                $(
102                    let $field = ToTokensCompat($field, crates);
103                )*
104                let alloy_sol_types = &crates.sol_types;
105                s.extend(quote! {
106                    #alloy_sol_types::private::alloy_json_abi::$name {
107                        $($field: #$field,)*
108                    }
109                });
110            }
111        }
112        derive_verbatim!($($rest)*);
113    };
114
115    (enum $name:ident { $($variant:ident $( { $($field_idx:tt : $field:ident),* $(,)? } )?),* $(,)? } $($rest:tt)*) => {
116        impl Verbatim for alloy_json_abi::$name {
117            fn to_verbatim_tokens(&self, s: &mut TokenStream, crates: &ExternCrates) {
118                match self {$(
119                    Self::$variant $( { $($field_idx: $field),* } )? => {
120                        $($(
121                            let $field = ToTokensCompat($field, crates);
122                        )*)?
123                        let alloy_sol_types = &crates.sol_types;
124                        s.extend(quote! {
125                            #alloy_sol_types::private::alloy_json_abi::$name::$variant $( { $($field_idx: #$field),* } )?
126                        });
127                    }
128                )*}
129            }
130        }
131        derive_verbatim!($($rest)*);
132    };
133}
134
135derive_verbatim! {
136    struct Constructor { inputs, state_mutability }
137    struct Fallback { state_mutability }
138    struct Receive { state_mutability }
139    struct Function { name, inputs, outputs, state_mutability }
140    struct Error { name, inputs }
141    struct Event { name, inputs, anonymous }
142    struct Param { ty, name, components, internal_type }
143    struct EventParam { ty, name, indexed, components, internal_type }
144
145    enum InternalType {
146        AddressPayable { 0: s },
147        Contract { 0: s },
148        Enum { contract: contract, ty: ty },
149        Struct { contract: contract, ty: ty },
150        Other { contract: contract, ty: ty },
151    }
152
153    enum StateMutability {
154        Pure,
155        View,
156        NonPayable,
157        Payable,
158    }
159}