Skip to main content

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            impl #name {
66                /// The Solidity type name.
67                pub const NAME: &'static str = stringify!(#name);
68
69                /// Convert from the underlying value type.
70                #[inline]
71                pub const fn from_underlying(value: #underlying_rust) -> Self {
72                    Self(value)
73                }
74
75                /// Return the underlying value.
76                #[inline]
77                pub const fn into_underlying(self) -> #underlying_rust {
78                    self.0
79                }
80
81                /// Return the single encoding of this value, delegating to the
82                /// underlying type.
83                #[inline]
84                pub fn abi_encode(&self) -> alloy_sol_types::private::Vec<u8> {
85                    <Self as alloy_sol_types::SolType>::abi_encode(&self.0)
86                }
87
88                /// Return the packed encoding of this value, delegating to the
89                /// underlying type.
90                #[inline]
91                pub fn abi_encode_packed(&self) -> alloy_sol_types::private::Vec<u8> {
92                    <Self as alloy_sol_types::SolType>::abi_encode_packed(&self.0)
93                }
94            }
95
96            #[automatically_derived]
97            impl From<#underlying_rust> for #name {
98                fn from(value: #underlying_rust) -> Self {
99                    Self::from_underlying(value)
100                }
101            }
102
103            #[automatically_derived]
104            impl From<#name> for #underlying_rust {
105                fn from(value: #name) -> Self {
106                    value.into_underlying()
107                }
108            }
109
110            #[automatically_derived]
111            impl alloy_sol_types::SolType for #name {
112                type RustType = #underlying_rust;
113                type Token<'a> = <#underlying_sol as alloy_sol_types::SolType>::Token<'a>;
114
115                const SOL_NAME: &'static str = Self::NAME;
116                const ENCODED_SIZE: Option<usize> = <#underlying_sol as alloy_sol_types::SolType>::ENCODED_SIZE;
117                const PACKED_ENCODED_SIZE: Option<usize> = <#underlying_sol as alloy_sol_types::SolType>::PACKED_ENCODED_SIZE;
118
119                #[inline]
120                fn valid_token(token: &Self::Token<'_>) -> bool {
121                    Self::type_check(token).is_ok()
122                }
123
124                #[inline]
125                fn type_check(token: &Self::Token<'_>) -> alloy_sol_types::Result<()> {
126                    #type_check_body
127                }
128
129                #[inline]
130                fn detokenize(token: Self::Token<'_>) -> Self::RustType {
131                    <#underlying_sol as alloy_sol_types::SolType>::detokenize(token)
132                }
133            }
134
135            #[automatically_derived]
136            impl alloy_sol_types::EventTopic for #name {
137                #[inline]
138                fn topic_preimage_length(rust: &Self::RustType) -> usize {
139                    <#underlying_sol as alloy_sol_types::EventTopic>::topic_preimage_length(rust)
140                }
141
142                #[inline]
143                fn encode_topic_preimage(rust: &Self::RustType, out: &mut alloy_sol_types::private::Vec<u8>) {
144                    <#underlying_sol as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, out)
145                }
146
147                #[inline]
148                fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken {
149                    <#underlying_sol as alloy_sol_types::EventTopic>::encode_topic(rust)
150                }
151            }
152        };
153    };
154    Ok(tokens)
155}