Skip to main content

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