From d604f6b14137feedd779f0b32b63266bd9a6ff8c Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Tue, 20 Jul 2021 17:25:52 +0000 Subject: [PATCH] feat: implement new solidity interface generator --- --- /dev/null +++ b/crates/evm-coder/src/solidity.rs @@ -0,0 +1,161 @@ +use core::{fmt, marker::PhantomData}; +use impl_trait_for_tuples::impl_for_tuples; +use crate::types::*; + +pub trait SolidityTypeName: 'static { + fn solidity_name(writer: &mut impl fmt::Write) -> fmt::Result; + fn is_void() -> bool { + false + } +} + +macro_rules! solidity_type_name { + ($($ty:ident => $name:expr),* $(,)?) => { + $( + impl SolidityTypeName for $ty { + fn solidity_name(writer: &mut impl core::fmt::Write) -> core::fmt::Result { + write!(writer, $name) + } + } + )* + }; +} + +solidity_type_name! { + uint8 => "uint8", + address => "address", + string => "memory string", +} +impl SolidityTypeName for void { + fn solidity_name(_writer: &mut impl fmt::Write) -> fmt::Result { + Ok(()) + } + fn is_void() -> bool { + true + } +} + +pub trait SolidityArguments { + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result; + fn is_empty(&self) -> bool { + self.len() == 0 + } + fn len(&self) -> usize; +} + +pub struct UnnamedArgument(PhantomData<*const T>); + +impl SolidityArguments for UnnamedArgument { + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { + if !T::is_void() { + T::solidity_name(writer) + } else { + Ok(()) + } + } + fn len(&self) -> usize { + if T::is_void() { + 0 + } else { + 1 + } + } +} + +pub struct NamedArgument(&'static str, PhantomData<*const T>); + +impl SolidityArguments for NamedArgument { + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { + if !T::is_void() { + T::solidity_name(writer)?; + write!(writer, " {}", self.0) + } else { + Ok(()) + } + } + fn len(&self) -> usize { + if T::is_void() { + 0 + } else { + 1 + } + } +} + +impl SolidityArguments for () { + fn solidity_name(&self, _writer: &mut impl fmt::Write) -> fmt::Result { + Ok(()) + } + fn len(&self) -> usize { + 0 + } +} + +#[impl_for_tuples(1, 5)] +impl SolidityArguments for Tuple { + for_tuples!( where #( Tuple: SolidityArguments ),* ); + + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { + let mut first = false; + for_tuples!( #( + if !Tuple.is_empty() { + if first { + write!(writer, ", ")?; + } + first = false; + Tuple.solidity_name(writer)?; + } + )* ); + Ok(()) + } + fn len(&self) -> usize { + for_tuples!( #( Tuple.len() )+* ) + } +} + +trait SolidityFunctions { + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result; +} + +pub enum SolidityMutability { + Pure, + View, + Mutable, +} +pub struct SolidityFunction { + name: &'static str, + args: A, + result: R, + mutability: SolidityMutability, +} +impl SolidityFunctions for SolidityFunction { + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { + write!(writer, "function {}(", self.name)?; + self.args.solidity_name(writer)?; + write!(writer, ") public")?; + match &self.mutability { + SolidityMutability::Pure => write!(writer, " pure")?, + SolidityMutability::View => write!(writer, " view")?, + SolidityMutability::Mutable => {} + } + if !self.result.is_empty() { + write!(writer, "returns (")?; + self.result.solidity_name(writer)?; + write!(writer, ")")?; + } + writeln!(writer, ";") + } +} + +#[impl_for_tuples(0, 12)] +impl SolidityFunctions for Tuple { + for_tuples!( where #( Tuple: SolidityFunctions ),* ); + + fn solidity_name(&self, writer: &mut impl fmt::Write) -> fmt::Result { + let mut first = false; + for_tuples!( #( + Tuple.solidity_name(writer)?; + )* ); + Ok(()) + } +} -- gitstuff