alloy_sol_macro_expander/expand/
udt.rs

1//! [`ItemUdt`] expansion.
2
3use super::ExpCtxt;
4use alloy_sol_macro_input::ContainsSolAttrs;
5use ast::ItemUdt;
6use proc_macro2::TokenStream;
7use quote::quote;
8use syn::Result;
9
10pub(super) fn expand(cx: &ExpCtxt<'_>, udt: &ItemUdt) -> Result<TokenStream> {
11    let ItemUdt { name, ty, .. } = udt;
12
13    let (sol_attrs, mut attrs) = udt.split_attrs()?;
14    cx.type_derives(&mut attrs, std::iter::once(ty), true);
15
16    let underlying_sol = cx.expand_type(ty);
17    let underlying_rust = cx.expand_rust_type(ty);
18
19    let type_check_body = if let Some(lit_str) = sol_attrs.type_check {
20        let func_path: syn::Path = lit_str.parse()?;
21        quote! {
22            <#underlying_sol as alloy_sol_types::SolType>::type_check(token)?;
23            #func_path(token)
24        }
25    } else {
26        quote! {
27            <#underlying_sol as alloy_sol_types::SolType>::type_check(token)
28        }
29    };
30
31    let alloy_sol_types = &cx.crates.sol_types;
32
33    let tokens = quote! {
34        #(#attrs)*
35        #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)]
36        #[derive(Clone)]
37        pub struct #name(#underlying_rust);
38
39        const _: () = {
40            use #alloy_sol_types as alloy_sol_types;
41
42            #[automatically_derived]
43            impl alloy_sol_types::private::SolTypeValue<#name> for #underlying_rust {
44                #[inline]
45                fn stv_to_tokens(&self) -> <#underlying_sol as alloy_sol_types::SolType>::Token<'_> {
46                    alloy_sol_types::private::SolTypeValue::<#underlying_sol>::stv_to_tokens(self)
47                }
48
49                #[inline]
50                fn stv_eip712_data_word(&self) -> alloy_sol_types::Word {
51                    <#underlying_sol as alloy_sol_types::SolType>::tokenize(self).0
52                }
53
54                #[inline]
55                fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec<u8>) {
56                    <#underlying_sol as alloy_sol_types::SolType>::abi_encode_packed_to(self, out)
57                }
58
59                #[inline]
60                fn stv_abi_packed_encoded_size(&self) -> usize {
61                    <#underlying_sol as alloy_sol_types::SolType>::abi_encoded_size(self)
62                }
63            }
64
65            #[automatically_derived]
66            impl #name {
67                /// The Solidity type name.
68                pub const NAME: &'static str = stringify!(@name);
69
70                /// Convert from the underlying value type.
71                #[inline]
72                pub const fn from(value: #underlying_rust) -> Self {
73                    Self(value)
74                }
75
76                /// Return the underlying value.
77                #[inline]
78                pub const fn into(self) -> #underlying_rust {
79                    self.0
80                }
81
82                /// Return the single encoding of this value, delegating to the
83                /// underlying type.
84                #[inline]
85                pub fn abi_encode(&self) -> alloy_sol_types::private::Vec<u8> {
86                    <Self as alloy_sol_types::SolType>::abi_encode(&self.0)
87                }
88
89                /// Return the packed encoding of this value, delegating to the
90                /// underlying type.
91                #[inline]
92                pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec<u8> {
93                    <Self as alloy_sol_types::SolType>::abi_encode_packed(&self.0)
94                }
95            }
96
97            #[automatically_derived]
98            impl alloy_sol_types::SolType for #name {
99                type RustType = #underlying_rust;
100                type Token<'a> = <#underlying_sol as alloy_sol_types::SolType>::Token<'a>;
101
102                const SOL_NAME: &'static str = Self::NAME;
103                const ENCODED_SIZE: Option<usize> = <#underlying_sol as alloy_sol_types::SolType>::ENCODED_SIZE;
104                const PACKED_ENCODED_SIZE: Option<usize> = <#underlying_sol as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE;
105
106                #[inline]
107                fn valid_token(token: &Self::Token<'_>) -> bool {
108                    Self::type_check(token).is_ok()
109                }
110
111                #[inline]
112                fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> {
113                    #type_check_body
114                }
115
116                #[inline]
117                fn detokenize(token: Self::Token<'_>) -> Self::RustType {
118                    <#underlying_sol as alloy_sol_types::SolType>::detokenize(token)
119                }
120            }
121
122            #[automatically_derived]
123            impl alloy_sol_types::EventTopic for #name {
124                #[inline]
125                fn topic_preimage_length(rust: &Self::RustType) -> usize {
126                    <#underlying_sol as alloy_sol_types::EventTopic>::topic_preimage_length(rust)
127                }
128
129                #[inline]
130                fn encode_topic_preimage(rust: &Self::RustType, out: &mut alloy_sol_types::private::Vec<u8>) {
131                    <#underlying_sol as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out)
132                }
133
134                #[inline]
135                fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken {
136                    <#underlying_sol as alloy_sol_types::EventTopic>::encode_topic(rust)
137                }
138            }
139        };
140    };
141    Ok(tokens)
142}