alloy_sol_macro_expander/expand/
error.rs1use super::{ExpCtxt, expand_fields, expand_from_into_tuples, expand_tokenize};
4use alloy_sol_macro_input::{ContainsSolAttrs, mk_doc};
5use ast::ItemError;
6use proc_macro2::TokenStream;
7use quote::quote;
8use syn::Result;
9
10pub(super) fn expand(cx: &ExpCtxt<'_>, error: &ItemError) -> Result<TokenStream> {
22 let ItemError { parameters: params, .. } = error;
23 cx.assert_resolved(params)?;
24
25 let (sol_attrs, mut attrs) = error.split_attrs()?;
26 cx.derives(&mut attrs, params, true);
27 let docs = sol_attrs.docs.or(cx.attrs.docs).unwrap_or(true);
28 let abi = sol_attrs.abi.or(cx.attrs.abi).unwrap_or(false);
29
30 let tokenize_impl = expand_tokenize(params, cx, super::FieldKind::Deconstruct);
31
32 let name = cx.overloaded_name(error.into());
33 let signature = cx.error_signature(error);
34 let selector = crate::utils::selector(&signature);
35
36 let alloy_sol_types = &cx.crates.sol_types;
37
38 let converts = expand_from_into_tuples(&name.0, params, cx, super::FieldKind::Deconstruct);
39
40 let doc = docs.then(|| {
41 let selector = hex::encode_prefixed(selector.array.as_slice());
42 mk_doc(format!(
43 "Custom error with signature `{signature}` and selector `{selector}`.\n\
44 ```solidity\n{error}\n```"
45 ))
46 });
47 let abi: Option<TokenStream> = abi.then(|| {
48 if_json! {
49 let error = super::to_abi::generate(error, cx);
50 quote! {
51 #[automatically_derived]
52 impl alloy_sol_types::JsonAbiExt for #name {
53 type Abi = alloy_sol_types::private::alloy_json_abi::Error;
54
55 fn abi() -> Self::Abi {
56 #error
57 }
58 }
59 }
60 }
61 });
62
63 let err_struct = match params.len() {
64 0 => {
65 quote! {
67 pub struct #name;
68 }
69 }
70 1 if params[0].name.is_none() => {
71 let ty = cx.expand_rust_type(¶ms[0].ty);
72 quote! {
74 pub struct #name(pub #ty);
75 }
76 }
77 _ => {
78 let fields = expand_fields(params, cx);
79 quote! {
80 pub struct #name {
81 #(#fields),*
82 }
83 }
84 }
85 };
86
87 let tokens = quote! {
88 #(#attrs)*
89 #doc
90 #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)]
91 #[derive(Clone)]
92 #err_struct
93
94 #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields, clippy::style)]
95 const _: () = {
96 use #alloy_sol_types as alloy_sol_types;
97
98 #converts
99
100 #[automatically_derived]
101 impl alloy_sol_types::SolError for #name {
102 type Parameters<'a> = UnderlyingSolTuple<'a>;
103 type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
104
105 const SIGNATURE: &'static str = #signature;
106 const SELECTOR: [u8; 4] = #selector;
107
108 #[inline]
109 fn new<'a>(tuple: <Self::Parameters<'a> as alloy_sol_types::SolType>::RustType) -> Self {
110 tuple.into()
111 }
112
113 #[inline]
114 fn tokenize(&self) -> Self::Token<'_> {
115 #tokenize_impl
116 }
117
118 #[inline]
119 fn abi_decode_raw_validate(data: &[u8]) -> alloy_sol_types::Result<Self> {
122 Self::abi_decode_raw_with_config(
123 data,
124 alloy_sol_types::abi::AbiDecoderConfig::new().validate(true),
125 )
126 }
127 }
128
129 #abi
130 };
131 };
132 Ok(tokens)
133}