1use proc_macro::TokenStream;
7use proc_macro2::Ident;
8use quote::{quote, ToTokens};
9use syn::{parse_macro_input, ImplItem, ItemEnum, ItemImpl};
10
11#[proc_macro_attribute]
33pub fn pyhash(_: TokenStream, item: TokenStream) -> TokenStream {
34 let mut ast = parse_macro_input!(item as ItemImpl);
35 let to_add = quote! {pub fn __hash__(&self) -> u64 {
36 solders_traits_core::PyHash::pyhash(self)
37 }};
38 ast.items.push(ImplItem::Verbatim(to_add));
39 TokenStream::from(ast.to_token_stream())
40}
41
42#[proc_macro_attribute]
65pub fn richcmp_full(_: TokenStream, item: TokenStream) -> TokenStream {
66 let mut ast = parse_macro_input!(item as ItemImpl);
67 let to_add = quote! {pub fn __richcmp__(&self, other: &Self, op: pyo3::basic::CompareOp) -> bool {
68 solders_traits_core::RichcmpFull::richcmp(self, other, op)
69 }};
70 ast.items.push(ImplItem::Verbatim(to_add));
71 TokenStream::from(ast.to_token_stream())
72}
73
74#[proc_macro_attribute]
76pub fn richcmp_eq_only(_: TokenStream, item: TokenStream) -> TokenStream {
77 let mut ast = parse_macro_input!(item as ItemImpl);
78 let to_add = quote! {pub fn __richcmp__(&self, other: &Self, op: pyo3::basic::CompareOp) -> pyo3::prelude::PyResult<bool> {
79 solders_traits_core::RichcmpEqualityOnly::richcmp(self, other, op)
80 }};
81 ast.items.push(ImplItem::Verbatim(to_add));
82 TokenStream::from(ast.to_token_stream())
83}
84
85#[proc_macro_attribute]
87pub fn richcmp_signer(_: TokenStream, item: TokenStream) -> TokenStream {
88 let mut ast = parse_macro_input!(item as ItemImpl);
89 let to_add = quote! {pub fn __richcmp__(&self, other: crate::signer::Signer, op: pyo3::basic::CompareOp) -> pyo3::prelude::PyResult<bool> {
90 solders_traits::RichcmpSigner::richcmp(self, other, op)
91 }};
92 ast.items.push(ImplItem::Verbatim(to_add));
93 TokenStream::from(ast.to_token_stream())
94}
95
96fn add_core_methods(ast: &mut ItemImpl) {
97 let mut methods = vec![
98 ImplItem::Verbatim(
99 quote! {pub fn __bytes__<'a>(&self, py: pyo3::prelude::Python<'a>) -> &'a pyo3::types::PyBytes {
100 solders_traits_core::CommonMethodsCore::pybytes(self, py)
101 }},
102 ),
103 ImplItem::Verbatim(quote! { pub fn __str__(&self) -> String {
104 solders_traits_core::CommonMethodsCore::pystr(self)
105 } }),
106 ImplItem::Verbatim(quote! { pub fn __repr__(&self) -> String {
107 solders_traits_core::CommonMethodsCore::pyrepr(self)
108 } }),
109 ImplItem::Verbatim(
110 quote! { pub fn __reduce__(&self) -> pyo3::prelude::PyResult<(pyo3::prelude::PyObject, pyo3::prelude::PyObject)> {
111 solders_traits_core::CommonMethodsCore::pyreduce(self)
112 } },
113 ),
114 ];
115 if !ast.items.iter().any(|item| match item {
116 ImplItem::Method(m) => m.sig.ident == "from_bytes",
117 _ => false,
118 }) {
119 let from_bytes = ImplItem::Verbatim(quote! {
120 #[staticmethod]
128 pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
129 <Self as solders_traits_core::CommonMethodsCore>::py_from_bytes(data)
130 }
131 });
132 methods.push(from_bytes);
133 };
134 ast.items.extend_from_slice(&methods);
135}
136
137#[proc_macro_attribute]
141pub fn common_methods_core(_: TokenStream, item: TokenStream) -> TokenStream {
142 let mut ast = parse_macro_input!(item as ItemImpl);
143 add_core_methods(&mut ast);
144 TokenStream::from(ast.to_token_stream())
145}
146
147#[proc_macro_attribute]
151pub fn common_methods(_: TokenStream, item: TokenStream) -> TokenStream {
152 let mut ast = parse_macro_input!(item as ItemImpl);
153 add_core_methods(&mut ast);
154 let methods = vec![
155 ImplItem::Verbatim(quote! {
156 pub fn to_json(&self) -> String {
158 solders_traits_core::CommonMethods::py_to_json(self)
159 } }),
160 ImplItem::Verbatim(quote! {
161 #[staticmethod] pub fn from_json(raw: &str) -> PyResult<Self> {
163 <Self as solders_traits_core::CommonMethods>::py_from_json(raw)
164 } }),
165 ];
166 ast.items.extend_from_slice(&methods);
167 TokenStream::from(ast.to_token_stream())
168}
169
170#[proc_macro_attribute]
172pub fn common_methods_rpc_resp(_: TokenStream, item: TokenStream) -> TokenStream {
173 let mut ast = parse_macro_input!(item as ItemImpl);
174 let methods = vec![
175 ImplItem::Verbatim(
176 quote! {pub fn __bytes__<'a>(&self, py: pyo3::prelude::Python<'a>) -> &'a pyo3::types::PyBytes {
177 CommonMethodsRpcResp::pybytes(self, py)
178 }},
179 ),
180 ImplItem::Verbatim(quote! { pub fn __str__(&self) -> String {
181 CommonMethodsRpcResp::pystr(self)
182 } }),
183 ImplItem::Verbatim(quote! { pub fn __repr__(&self) -> String {
184 CommonMethodsRpcResp::pyrepr(self)
185 } }),
186 ImplItem::Verbatim(
187 quote! { pub fn __reduce__(&self) -> pyo3::prelude::PyResult<(pyo3::prelude::PyObject, pyo3::prelude::PyObject)> {
188 CommonMethodsRpcResp::pyreduce(self)
189 } },
190 ),
191 ImplItem::Verbatim(quote! {
192 pub fn to_json(&self) -> String {
194 CommonMethodsRpcResp::py_to_json(self)
195 } }),
196 ImplItem::Verbatim(quote! {
197 #[staticmethod]
206 pub fn from_json(raw: &str) -> PyResult<Resp<Self>> {
207 <Self as CommonMethodsRpcResp>::py_from_json(raw)
208 } }),
209 ImplItem::Verbatim(quote! {
210 #[staticmethod]
218 pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
219 <Self as CommonMethodsRpcResp>::py_from_bytes(data)
220 }
221 }),
222 ImplItem::Verbatim(
223 quote! {pub fn __richcmp__(&self, other: &Self, op: pyo3::basic::CompareOp) -> pyo3::prelude::PyResult<bool> {
224 solders_traits_core::RichcmpEqualityOnly::richcmp(self, other, op)
225 }},
226 ),
227 ];
228 ast.items.extend_from_slice(&methods);
229 TokenStream::from(ast.to_token_stream())
230}
231
232#[proc_macro_attribute]
236pub fn rpc_id_getter(_: TokenStream, item: TokenStream) -> TokenStream {
237 let mut ast = parse_macro_input!(item as ItemImpl);
238 let to_add = quote! {
239 #[getter]
241 pub fn id(&self) -> u64 {
242 self.base.id
243 }};
244 ast.items.push(ImplItem::Verbatim(to_add));
245 TokenStream::from(ast.to_token_stream())
246}
247
248#[proc_macro_attribute]
273pub fn enum_original_mapping(original: TokenStream, item: TokenStream) -> TokenStream {
274 let mut new_stream = proc_macro2::TokenStream::from(item.clone());
275 let ast = parse_macro_input!(item as ItemEnum);
276 let enum_name = ast.ident;
277 let orig = parse_macro_input!(original as Ident);
278 let variant_names: Vec<Ident> = ast.variants.into_iter().map(|v| v.ident).collect();
279 let from_impl = quote! {
280 impl From<#orig> for #enum_name {
281 fn from(left: #orig) -> Self {
282 match left {
283 #(#orig::#variant_names => Self::#variant_names),*,
284 _ => panic!("Unrecognized variant: {:?}", left)
285 }
286 }
287 }
288
289 impl From<#enum_name> for #orig {
290 fn from(left: #enum_name) -> Self {
291 match left {
292 #(#enum_name::#variant_names => Self::#variant_names),*
293 }
294 }
295 }
296 };
297 new_stream.extend(from_impl);
298 TokenStream::from(new_stream)
299}
300
301#[proc_macro_derive(EnumIntoPy)]
315pub fn enum_into_py(item: TokenStream) -> TokenStream {
316 let ast = parse_macro_input!(item as ItemEnum);
317 let enum_name = ast.ident;
318 let variant_names: Vec<Ident> = ast.variants.into_iter().map(|v| v.ident).collect();
319 let into_py_impl = quote! {
320 impl IntoPy<PyObject> for #enum_name {
321 fn into_py(self, py: Python<'_>) -> PyObject {
322 match self {
323 #(Self::#variant_names(x) => x.into_py(py)),*,
324 }
325 }
326 }
327 };
328 into_py_impl.to_token_stream().into()
329}