Skip to content

Commit

Permalink
chore: Cleanup in entry_points macro
Browse files Browse the repository at this point in the history
  • Loading branch information
jawoznia committed Jul 31, 2024
1 parent 5bde982 commit 7b6d2ce
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 152 deletions.
3 changes: 2 additions & 1 deletion sylvia-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod variant_descs;
use strip_input::StripInput;

use crate::message::EntryPoints;
use crate::parser::EntryPointArgs;

#[cfg(not(test))]
pub(crate) fn crate_module() -> Path {
Expand Down Expand Up @@ -757,8 +758,8 @@ pub fn entry_points(attr: TokenStream, item: TokenStream) -> TokenStream {

fn entry_points_impl(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
fn inner(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> {
let attrs: parser::EntryPointArgs = parse2(attr)?;
let input: ItemImpl = parse2(item)?;
let attrs = EntryPointArgs::new(&attr, &input)?;
let expanded = EntryPoints::new(&input, attrs).emit();

Ok(quote! {
Expand Down
235 changes: 104 additions & 131 deletions sylvia-derive/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ use proc_macro2::{Span, TokenStream};
use proc_macro_error::emit_error;
use quote::{quote, ToTokens};
use syn::fold::Fold;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::visit::Visit;
use syn::{
parse_quote, Attribute, GenericArgument, GenericParam, Ident, ImplItem, ImplItemFn, ItemImpl,
ItemTrait, Pat, PatType, ReturnType, Signature, Token, Type, WhereClause, WherePredicate,
parse_quote, Attribute, GenericParam, Ident, ImplItem, ImplItemFn, ItemImpl, ItemTrait, Pat,
PatType, ReturnType, Signature, Type, WhereClause, WherePredicate,
};

/// Representation of single struct message
Expand Down Expand Up @@ -660,41 +659,6 @@ where
&self.unused_generics
}

pub fn emit_default_entry_point(
&self,
custom_msg: &Type,
custom_query: &Type,
name: &Type,
error: &Type,
contract_generics: &Option<Punctuated<GenericArgument, Token![,]>>,
) -> TokenStream {
let Self { msg_ty, .. } = self;
let sylvia = crate_module();

let resp_type = match msg_ty {
MsgType::Query => quote! { #sylvia ::cw_std::Binary },
_ => quote! { #sylvia ::cw_std::Response < #custom_msg > },
};
let params = msg_ty.emit_ctx_params(custom_query);
let values = msg_ty.emit_ctx_values();
let ep_name = msg_ty.emit_ep_name();
let bracketed_generics = match &contract_generics {
Some(generics) => quote! { ::< #generics > },
None => quote! {},
};
let associated_name = msg_ty.as_accessor_wrapper_name();

quote! {
#[#sylvia ::cw_std::entry_point]
pub fn #ep_name (
#params ,
msg: < #name < #contract_generics > as #sylvia ::types::ContractApi> :: #associated_name,
) -> Result<#resp_type, #error> {
msg.dispatch(&#name #bracketed_generics ::new() , ( #values )).map_err(Into::into)
}
}
}

pub fn emit_phantom_match_arm(&self) -> TokenStream {
let sylvia = crate_module();
let Self { used_generics, .. } = self;
Expand Down Expand Up @@ -1296,6 +1260,7 @@ pub struct EntryPoints<'a> {
source: &'a ItemImpl,
name: Type,
error: Type,
reply: Option<Ident>,
override_entry_points: Vec<OverrideEntryPoint>,
generics: Vec<&'a GenericParam>,
where_clause: &'a Option<WhereClause>,
Expand All @@ -1313,10 +1278,17 @@ impl<'a> EntryPoints<'a> {
let generics: Vec<_> = source.generics.params.iter().collect();
let where_clause = &source.generics.where_clause;

let reply =
MsgVariants::<GenericParam>::new(source.as_variants(), MsgType::Reply, &[], &None)
.variants()
.map(|variant| variant.function_name.clone())
.next();

Self {
source,
name,
error,
reply,
override_entry_points,
generics,
where_clause,
Expand All @@ -1327,119 +1299,120 @@ impl<'a> EntryPoints<'a> {
pub fn emit(&self) -> TokenStream {
let Self {
source,
name,
error,
reply,
override_entry_points,
generics,
where_clause,
attrs,
..
} = self;
let sylvia = crate_module();

let bracketed_generics = attrs
.generics
.as_ref()
.map(|generics| match generics.is_empty() {
true => quote! {},
false => quote! { < #generics > },
})
.unwrap_or(quote! {});

let custom_msg = parse_quote! { < #name #bracketed_generics as #sylvia ::types::ContractApi > :: CustomMsg };
let custom_query = parse_quote! { < #name #bracketed_generics as #sylvia ::types::ContractApi > :: CustomQuery };

let instantiate_variants = MsgVariants::new(
source.as_variants(),
let entry_points = [
MsgType::Instantiate,
generics,
where_clause,
MsgType::Exec,
MsgType::Query,
MsgType::Sudo,
]
.into_iter()
.map(
|msg_ty| match override_entry_points.get_entry_point(msg_ty) {
Some(_) => quote! {},
None => self.emit_default_entry_point(msg_ty),
},
);
let exec_variants =
MsgVariants::new(source.as_variants(), MsgType::Exec, generics, where_clause);
let query_variants =
MsgVariants::new(source.as_variants(), MsgType::Query, generics, where_clause);
let migrate_variants = MsgVariants::new(

let is_migrate = MsgVariants::new(
source.as_variants(),
MsgType::Migrate,
generics,
where_clause,
);
let reply =
MsgVariants::<GenericParam>::new(source.as_variants(), MsgType::Reply, &[], &None)
.variants()
.map(|variant| variant.function_name.clone())
.next();
let sudo_variants =
MsgVariants::new(source.as_variants(), MsgType::Sudo, generics, where_clause);
let contract_generics = match &attrs.generics {
Some(generics) => quote! { ::< #generics > },
None => quote! {},
)
.get_only_variant()
.is_some();

let migrate_not_overridden = override_entry_points
.get_entry_point(MsgType::Migrate)
.is_none();

let migrate = if migrate_not_overridden && is_migrate {
self.emit_default_entry_point(MsgType::Migrate)
} else {
quote! {}
};

{
let entry_points = [
instantiate_variants,
exec_variants,
query_variants,
sudo_variants,
]
.into_iter()
.map(|variants| {
match override_entry_points.get_entry_point(variants.msg_ty) {
Some(_) => quote! {},
None => variants.emit_default_entry_point(
&custom_msg,
&custom_query,
name,
error,
&attrs.generics,
),
let reply_ep = override_entry_points
.get_entry_point(MsgType::Reply)
.map(|_| quote! {})
.unwrap_or_else(|| {
if reply.is_some() {
self.emit_default_entry_point(MsgType::Reply)
} else {
quote! {}
}
});

let migrate_not_overridden = override_entry_points
.get_entry_point(MsgType::Migrate)
.is_none();

let migrate = if migrate_not_overridden && migrate_variants.get_only_variant().is_some()
{
migrate_variants.emit_default_entry_point(
&custom_msg,
&custom_query,
name,
error,
&attrs.generics,
)
} else {
quote! {}
};

let reply_ep = override_entry_points.get_entry_point(MsgType::Reply)
.map(|_| quote! {})
.unwrap_or_else(|| match reply {
Some(reply) => quote! {
#[#sylvia ::cw_std::entry_point]
pub fn reply(
deps: #sylvia ::cw_std::DepsMut< #custom_query >,
env: #sylvia ::cw_std::Env,
msg: #sylvia ::cw_std::Reply,
) -> Result<#sylvia ::cw_std::Response < #custom_msg >, #error> {
#name #contract_generics ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
}
},
_ => quote! {},
});
quote! {
pub mod entry_points {
use super::*;

quote! {
pub mod entry_points {
use super::*;
#(#entry_points)*

#(#entry_points)*
#migrate

#migrate
#reply_ep
}
}
}

#reply_ep
}
pub fn emit_default_entry_point(&self, msg_ty: MsgType) -> TokenStream {
let Self {
name,
error,
attrs,
reply,
..
} = self;
let sylvia = crate_module();

let attr_generics = &attrs.generics;
let (contract, contract_turbo) = if attr_generics.is_empty() {
(quote! { #name }, quote! { #name })
} else {
(
quote! { #name < #attr_generics > },
quote! { #name :: < #attr_generics > },
)
};

let custom_msg: Type =
parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomMsg };
let custom_query: Type =
parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomQuery };

let result = msg_ty.emit_result_type(&custom_msg, error);
let params = msg_ty.emit_ctx_params(&custom_query);
let values = msg_ty.emit_ctx_values();
let ep_name = msg_ty.emit_ep_name();
let associated_name = msg_ty.as_accessor_wrapper_name();
let msg = match msg_ty {
MsgType::Reply => quote! { msg: #sylvia ::cw_std::Reply },
_ => quote! { msg: < #contract as #sylvia ::types::ContractApi> :: #associated_name },
};
let dispatch = match msg_ty {
MsgType::Reply => quote! {
#contract_turbo ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
},
_ => quote! {
msg.dispatch(& #contract_turbo ::new() , ( #values )).map_err(Into::into)
},
};

quote! {
#[#sylvia ::cw_std::entry_point]
pub fn #ep_name (
#params ,
#msg
) -> #result {
#dispatch
}
}
}
Expand Down
27 changes: 24 additions & 3 deletions sylvia-derive/src/parser/entry_point.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error::emit_error;
use syn::parse::{Error, Nothing, Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{GenericArgument, Path, Result, Token};
use syn::{parse2, GenericArgument, ItemImpl, Path, Result, Token};

use super::extract_generics_from_path;

/// Parsed arguments for `entry_points` macro
#[derive(Default)]
pub struct EntryPointArgs {
/// Types used in place of contracts generics.
pub generics: Option<Punctuated<GenericArgument, Token![,]>>,
pub generics: Punctuated<GenericArgument, Token![,]>,
}

impl EntryPointArgs {
pub fn new(attr: &TokenStream2, source: &ItemImpl) -> Result<Self> {
let args: Self = parse2(attr.clone()).map_err(|err| {
emit_error!(attr, err);
err
})?;

if args.generics.len() != source.generics.params.len() {
emit_error!(
attr.span(),
"Missing concrete types.";
note = "For every generic type in the contract, a concrete type must be provided in `#[entry_points(generics<T1, T2, ...>)]`.";
);
}

Ok(args)
}
}

impl Parse for EntryPointArgs {
Expand All @@ -22,7 +43,7 @@ impl Parse for EntryPointArgs {
let generics: Path = input.parse()?;
match generics.segments.last() {
Some(segment) if segment.ident == "generics" => {
entry_points_args.generics = Some(extract_generics_from_path(&generics))
entry_points_args.generics = extract_generics_from_path(&generics)
}
_ => return Err(Error::new(generics.span(), "Expected `generics`.")),
};
Expand Down
Loading

0 comments on commit 7b6d2ce

Please sign in to comment.