-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #105 from OffchainLabs/derive-solidity-error
Full `#[derive(SolidityError)]`
- Loading branch information
Showing
15 changed files
with
279 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Copyright 2024, Offchain Labs, Inc. | ||
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/stylus/licenses/COPYRIGHT.md | ||
|
||
use proc_macro::TokenStream; | ||
use quote::quote; | ||
use syn::{parse_macro_input, Fields, ItemEnum}; | ||
|
||
pub fn derive_solidity_error(input: TokenStream) -> TokenStream { | ||
let input = parse_macro_input!(input as ItemEnum); | ||
let name = &input.ident; | ||
let mut match_arms = quote!(); | ||
let mut errors = vec![]; | ||
for variant in input.variants { | ||
let variant_name = variant.ident; | ||
let error = match variant.fields { | ||
Fields::Unnamed(e) if variant.fields.len() == 1 => e.unnamed.first().unwrap().clone(), | ||
_ => error!(variant.fields, "Variant not a 1-tuple"), | ||
}; | ||
match_arms.extend(quote! { | ||
#name::#variant_name(e) => stylus_sdk::alloy_sol_types::SolError::encode(&e), | ||
}); | ||
errors.push(error); | ||
} | ||
let mut output = quote! { | ||
impl From<#name> for alloc::vec::Vec<u8> { | ||
fn from(err: #name) -> alloc::vec::Vec<u8> { | ||
match err { | ||
#match_arms | ||
} | ||
} | ||
} | ||
}; | ||
|
||
if cfg!(feature = "export-abi") { | ||
output.extend(quote! { | ||
impl stylus_sdk::abi::export::internal::InnerTypes for #name { | ||
fn inner_types() -> alloc::vec::Vec<stylus_sdk::abi::export::internal::InnerType> { | ||
use alloc::{format, vec}; | ||
use core::any::TypeId; | ||
use stylus_sdk::abi::export::internal::InnerType; | ||
use stylus_sdk::alloy_sol_types::SolError; | ||
|
||
vec![ | ||
#( | ||
InnerType { | ||
name: format!("error {};", <#errors as SolError>::SIGNATURE.replace(',', ", ")), | ||
id: TypeId::of::<#errors>(), | ||
} | ||
),* | ||
] | ||
} | ||
} | ||
}); | ||
} | ||
|
||
output.into() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2024, Offchain Labs, Inc. | ||
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/stylus/licenses/COPYRIGHT.md | ||
|
||
//! This module provides functions for code generated by `stylus-sdk-proc` for the `export-abi` command. | ||
//! Most users shouldn't call these. | ||
use alloy_primitives::{Address, FixedBytes, Signed, Uint}; | ||
use core::any::TypeId; | ||
|
||
/// Represents a unique Solidity Type. | ||
pub struct InnerType { | ||
/// Full interface string. | ||
pub name: String, | ||
/// Unique identifier for de-duplication when printing interfaces. | ||
pub id: TypeId, | ||
} | ||
|
||
/// Trait for collecting structs and error types. | ||
pub trait InnerTypes { | ||
/// Collect any structs and errors under the type. | ||
/// Empty for primitives. | ||
fn inner_types() -> Vec<InnerType> { | ||
vec![] | ||
} | ||
} | ||
|
||
impl<O, E> InnerTypes for Result<O, E> | ||
where | ||
O: InnerTypes, | ||
E: InnerTypes, | ||
{ | ||
fn inner_types() -> Vec<InnerType> { | ||
let mut out = O::inner_types(); | ||
out.extend(E::inner_types()); | ||
out | ||
} | ||
} | ||
|
||
impl<T: InnerTypes> InnerTypes for Vec<T> { | ||
fn inner_types() -> Vec<InnerType> { | ||
T::inner_types() | ||
} | ||
} | ||
|
||
impl<const N: usize, T: InnerTypes> InnerTypes for [T; N] { | ||
fn inner_types() -> Vec<InnerType> { | ||
T::inner_types() | ||
} | ||
} | ||
|
||
macro_rules! impl_inner { | ||
($ty:ident $($rest:ident)+) => { | ||
impl_inner!($ty); | ||
impl_inner!($($rest)+); | ||
}; | ||
($ty:ident) => { | ||
impl InnerTypes for $ty {} | ||
}; | ||
} | ||
|
||
impl_inner!(bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 String Address); | ||
|
||
impl<const B: usize, const L: usize> InnerTypes for Uint<B, L> {} | ||
impl<const B: usize, const L: usize> InnerTypes for Signed<B, L> {} | ||
impl<const N: usize> InnerTypes for FixedBytes<N> {} | ||
|
||
macro_rules! impl_tuple { | ||
() => { | ||
impl InnerTypes for () {} | ||
}; | ||
($first:ident $(, $rest:ident)*) => { | ||
impl<$first: InnerTypes $(, $rest: InnerTypes)*> InnerTypes for ( $first $(, $rest)* , ) { | ||
fn inner_types() -> Vec<InnerType> { | ||
vec![] | ||
} | ||
} | ||
|
||
impl_tuple! { $($rest),* } | ||
}; | ||
} | ||
|
||
impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.