git.delta.rocks / unique-network / refs/commits / f3ac592dce90

difftreelog

refactor external generation of call parsers

Yaroslav Bolyukin2021-07-20parent: #99e7a93.patch.diff
in: master

4 files changed

modifiedcrates/evm-coder-macros/src/lib.rsdiffbeforeafterboth
5use proc_macro::TokenStream;5use proc_macro::TokenStream;
6use quote::quote;6use quote::quote;
7use sha3::{Digest, Keccak256};7use sha3::{Digest, Keccak256};
8use syn::{8use syn::{AttributeArgs, DeriveInput, GenericArgument, Ident, ItemImpl, Pat, Path, PathArguments, PathSegment, Type, parse_macro_input, spanned::Spanned};
9 AttributeArgs, DeriveInput, GenericArgument, Ident, ItemTrait, Pat, Path, PathArguments,
10 PathSegment, Type, parse_macro_input, spanned::Spanned,
11};
129
13mod solidity_interface;10mod solidity_interface;
189 let args = parse_macro_input!(args as AttributeArgs);186 let args = parse_macro_input!(args as AttributeArgs);
190 let args = solidity_interface::InterfaceInfo::from_list(&args).unwrap();187 let args = solidity_interface::InterfaceInfo::from_list(&args).unwrap();
191188
192 let input: ItemTrait = match syn::parse(stream) {189 let input: ItemImpl = match syn::parse(stream) {
193 Ok(t) => t,190 Ok(t) => t,
194 Err(e) => return e.to_compile_error().into(),191 Err(e) => return e.to_compile_error().into(),
195 };192 };
196193
197 match solidity_interface::SolidityInterface::try_from(args, &input) {194 let expanded = match solidity_interface::SolidityInterface::try_from(args, &input) {
198 Ok(v) => v.expand(),195 Ok(v) => v.expand(),
199 Err(e) => e.to_compile_error(),196 Err(e) => e.to_compile_error(),
200 }197 };
198
199 (quote! {
200 #input
201
202 #expanded
201 .into()203 }).into()
202}204}
203205
204#[proc_macro_attribute]206#[proc_macro_attribute]
modifiedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth
4use darling::FromMeta;4use darling::FromMeta;
5use inflector::cases;5use inflector::cases;
6use std::fmt::Write;6use std::fmt::Write;
7use syn::{FnArg, Ident, ItemTrait, Meta, NestedMeta, PatType, Path, ReturnType, TraitItem, TraitItemMethod, Type, Visibility, spanned::Spanned};7use syn::{
8 FnArg, Ident, ImplItem, ImplItemMethod, ItemImpl, Meta, NestedMeta, PatType, Path, ReturnType,
9 Type, spanned::Spanned,
10};
811
9use crate::{12use crate::{
5154
52 fn expand_variant_call(&self) -> proc_macro2::TokenStream {55 fn expand_variant_call(&self) -> proc_macro2::TokenStream {
53 let name = &self.name;56 let name = &self.name;
54 let snake_call_name = &self.snake_call_name;57 let pascal_call_name = &self.pascal_call_name;
55 quote! {58 quote! {
56 InternalCall::#name(call) => return self.#snake_call_name(Msg {59 InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {
57 call,60 call,
58 caller: c.caller,61 caller: c.caller,
59 value: c.value,62 value: c.value,
60 })63 })
61 }64 }
62 }65 }
63
64 fn expand_call_inner(&self) -> proc_macro2::TokenStream {
65 let snake_call_name = &self.snake_call_name;
66 let pascal_call_name = &self.pascal_call_name;
67 quote! {
68 fn #snake_call_name(&mut self, c: Msg<#pascal_call_name>) -> Result<::evm_coder::abi::AbiWriter>;
69 }
70 }
7166
72 fn expand_parse(&self) -> proc_macro2::TokenStream {67 fn expand_parse(&self) -> proc_macro2::TokenStream {
73 let name = &self.name;68 let name = &self.name;
9792
98#[derive(FromMeta)]93#[derive(FromMeta)]
99pub struct InterfaceInfo {94pub struct InterfaceInfo {
95 name: Ident,
100 #[darling(default)]96 #[darling(default)]
101 is: IsList,97 is: IsList,
102 #[darling(default)]98 #[darling(default)]
192 result: Type,188 result: Type,
193}189}
194impl Method {190impl Method {
195 fn try_from(value: &TraitItemMethod) -> syn::Result<Self> {191 fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {
196 let mut info = MethodInfo {192 let mut info = MethodInfo {
197 rename_selector: None,193 rename_selector: None,
198 };194 };
386}382}
387383
388pub struct SolidityInterface {384pub struct SolidityInterface {
389 vis: Visibility,385 name: Box<syn::Type>,
390 name: Ident,386 ident: Ident,
391 info: InterfaceInfo,387 info: InterfaceInfo,
392 methods: Vec<Method>,388 methods: Vec<Method>,
393 items: Vec<TraitItem>,
394}389}
395impl SolidityInterface {390impl SolidityInterface {
396 pub fn try_from(info: InterfaceInfo, value: &ItemTrait) -> syn::Result<Self> {391 pub fn try_from(info: InterfaceInfo, value: &ItemImpl) -> syn::Result<Self> {
397 let mut methods = Vec::new();392 let mut methods = Vec::new();
398393
399 for item in &value.items {394 for item in &value.items {
400 match item {395 if let ImplItem::Method(method) = item {
401 TraitItem::Method(method) => methods.push(Method::try_from(method)?),396 methods.push(Method::try_from(method)?)
402 _ => {}
403 }397 }
404 }398 }
405 Ok(Self {399 Ok(Self {
406 vis: value.vis.clone(),400 name: value.self_ty.clone(),
407 name: value.ident.clone(),401 ident: parse_ident_from_type(&value.self_ty)?.clone(),
408 info,402 info,
409 methods,403 methods,
410 items: value.items.clone(),
411 })404 })
412 }405 }
413 pub fn expand(self) -> proc_macro2::TokenStream {406 pub fn expand(self) -> proc_macro2::TokenStream {
414 let vis = self.vis;
415 let name = self.name;407 let name = self.name;
416 let items = self.items;
417408
418 let call_name = pascal_ident_to_call(&name);409 let call_name = pascal_ident_to_call(&self.info.name);
419410
420 let call_sub = self411 let call_sub = self
421 .info412 .info
424 .iter()415 .iter()
425 .chain(self.info.is.0.iter())416 .chain(self.info.is.0.iter())
426 .map(Is::expand_call_def);417 .map(Is::expand_call_def);
427 let call_inner = self
428 .info
429 .inline_is
430 .0
431 .iter()
432 .chain(self.info.is.0.iter())
433 .map(Is::expand_call_inner);
434 let call_parse = self418 let call_parse = self
435 .info419 .info
436 .inline_is420 .inline_is
459443
460 quote! {444 quote! {
461 #[derive(Debug)]445 #[derive(Debug)]
462 #vis enum #call_name {446 pub enum #call_name {
463 #(447 #(
464 #calls,448 #calls,
465 )*449 )*
501 return Ok(None);485 return Ok(None);
502 }486 }
503 }487 }
504 #vis trait #name {
505 #(
506 #items
507 )*
508 #(
509 #call_inner
510 )*
511 }
512 impl<T> ::evm_coder::Callable for T where T: #name {488 impl ::evm_coder::Callable<#call_name> for #name {
513 type Call = #call_name;
514 #[allow(unreachable_code)] // In case of no inner calls489 #[allow(unreachable_code)] // In case of no inner calls
515 fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {490 fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {
516 use ::evm_coder::abi::AbiWrite;491 use ::evm_coder::abi::AbiWrite;
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
57 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;57 fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;
58}58}
5959
60pub trait Callable {60pub trait Callable<C: Call> {
61 type Call: Call;
62 fn call(&mut self, call: types::Msg<Self::Call>) -> execution::Result<AbiWriter>;61 fn call(&mut self, call: types::Msg<C>) -> execution::Result<AbiWriter>;
63}62}
6463
65#[cfg(test)]64#[cfg(test)]
66mod tests {65mod tests {
modifiedcrates/evm-coder/tests/a.rsdiffbeforeafterboth
3use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};3use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};
4use evm_coder_macros::solidity;4use evm_coder_macros::solidity;
5
6struct Impls;
57
6#[solidity_interface]8#[solidity_interface(name = "OurInterface")]
7trait OurInterface {9impl Impls {
8 fn fn_a(&self, input: uint256) -> Result<bool>;10 fn fn_a(&self, input: uint256) -> Result<bool> {
11 todo!()
12 }
9}13}
1014
11#[solidity_interface]15#[solidity_interface(name = "OurInterface1")]
12trait OurInterface1 {16impl Impls {
13 fn fn_b(&self, input: uint128) -> Result<uint32>;17 fn fn_b(&self, input: uint128) -> Result<uint32> {
18 todo!()
19 }
14}20}
1521
16#[solidity_interface(is(OurInterface), inline_is(OurInterface1), events(ERC721Log))]22#[solidity_interface(name = "OurInterface2", is(OurInterface), inline_is(OurInterface1), events(ERC721Log))]
17trait OurInterface2 {23impl Impls {
18 #[solidity(rename_selector = "fnK")]24 #[solidity(rename_selector = "fnK")]
19 fn fn_c(&self, input: uint32) -> Result<uint8>;25 fn fn_c(&self, input: uint32) -> Result<uint8> {
26 todo!()
27 }
20 fn fn_d(&self, value: uint32) -> Result<uint32>;28 fn fn_d(&self, value: uint32) -> Result<uint32> {
29 todo!()
30 }
2131
22 fn caller_sensitive(&self, caller: caller) -> Result<uint8>;32 fn caller_sensitive(&self, caller: caller) -> Result<uint8> {
33 todo!()
34 }
23 fn payable(&mut self, value: value) -> Result<uint8>;35 fn payable(&mut self, value: value) -> Result<uint8> {
36 todo!()
37 }
24}38}
2539
26#[derive(ToLog)]40#[derive(ToLog)]
39 },53 },
40}54}
55
56struct ERC20;
4157
42#[solidity_interface]58#[solidity_interface(name = "ERC20")]
43trait ERC20 {59impl ERC20 {
44 fn decimals(&self) -> Result<uint8>;60 fn decimals(&self) -> Result<uint8> {
61 todo!()
62 }
45 fn balance_of(&self, owner: address) -> Result<uint256>;63 fn balance_of(&self, owner: address) -> Result<uint256> {
64 todo!()
65 }
46 fn transfer(&mut self, caller: caller, to: address, value: uint256) -> Result<bool>;66 fn transfer(&mut self, caller: caller, to: address, value: uint256) -> Result<bool> {
67 todo!()
68 }
47 fn transfer_from(69 fn transfer_from(
48 &mut self,70 &mut self,
49 caller: caller,71 caller: caller,
50 from: address,72 from: address,
51 to: address,73 to: address,
52 value: uint256,74 value: uint256,
53 ) -> Result<bool>;75 ) -> Result<bool> {
76 todo!()
77 }
54 fn approve(&mut self, caller: caller, spender: address, value: uint256) -> Result<bool>;78 fn approve(&mut self, caller: caller, spender: address, value: uint256) -> Result<bool> {
79 todo!()
80 }
55 fn allowance(&self, owner: address, spender: address) -> Result<uint256>;81 fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
82 todo!()
83 }
56}84}
5785