Skip to content

Commit

Permalink
feat: Support generic types in entry points
Browse files Browse the repository at this point in the history
  • Loading branch information
jawoznia committed Nov 13, 2023
1 parent 11f56ab commit cc11f29
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 36 deletions.
30 changes: 24 additions & 6 deletions examples/contracts/generic_contract/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,54 @@
use cosmwasm_std::{Reply, Response, StdResult};
use cw_storage_plus::Item;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use sylvia::types::{
CustomMsg, ExecCtx, InstantiateCtx, MigrateCtx, QueryCtx, ReplyCtx, SvCustomMsg,
};
use sylvia::{contract, schemars};

pub struct GenericContract<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType>(
std::marker::PhantomData<(
#[cfg(not(feature = "library"))]
use sylvia::entry_points;

pub struct GenericContract<
InstantiateParam,
ExecParam,
QueryParam,
MigrateParam,
RetType,
FieldType,
> {
_field: Item<'static, FieldType>,
_phantom: std::marker::PhantomData<(
InstantiateParam,
ExecParam,
QueryParam,
MigrateParam,
RetType,
)>,
);
}

#[cfg_attr(not(feature = "library"), entry_points(generics<SvCustomMsg, SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg, SvCustomMsg, String>))]
#[contract]
#[messages(cw1 as Cw1: custom(msg))]
#[messages(generic<SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg> as Generic: custom(msg))]
#[messages(custom_and_generic<SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg> as CustomAndGeneric)]
#[sv::custom(msg=SvCustomMsg)]
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType>
GenericContract<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType>
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType, FieldType>
GenericContract<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType, FieldType>
where
for<'msg_de> InstantiateParam: CustomMsg + Deserialize<'msg_de> + 'msg_de,
ExecParam: CustomMsg + DeserializeOwned + 'static,
QueryParam: CustomMsg + DeserializeOwned + 'static,
MigrateParam: CustomMsg + DeserializeOwned + 'static,
RetType: CustomMsg + DeserializeOwned + 'static,
FieldType: 'static,
{
pub const fn new() -> Self {
Self(std::marker::PhantomData)
Self {
_field: Item::new("field"),
_phantom: std::marker::PhantomData,
}
}

#[msg(instantiate)]
Expand Down Expand Up @@ -92,6 +109,7 @@ mod tests {
SvCustomMsg,
super::SvCustomMsg,
super::SvCustomMsg,
String,
_,
> = CodeId::store_code(&app);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg};
#[contract(module = crate::contract)]
#[messages(custom_and_generic as CustomAndGeneric)]
#[sv::custom(msg=sylvia::types::SvCustomMsg)]
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType>
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType, FieldType>
CustomAndGeneric<SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg>
for crate::contract::GenericContract<
InstantiateParam,
ExecParam,
QueryParam,
MigrateParam,
RetType,
FieldType,
>
{
type Error = StdError;
Expand Down Expand Up @@ -52,6 +53,7 @@ mod tests {
SvCustomMsg,
SvCustomMsg,
sylvia::types::SvCustomMsg,
String,
_,
>::store_code(&app);

Expand Down
4 changes: 3 additions & 1 deletion examples/contracts/generic_contract/src/cw1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ use sylvia::types::{ExecCtx, QueryCtx};
#[contract(module = crate::contract)]
#[messages(cw1 as Cw1)]
#[sv::custom(msg=sylvia::types::SvCustomMsg)]
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType> Cw1
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType, FieldType> Cw1
for crate::contract::GenericContract<
InstantiateParam,
ExecParam,
QueryParam,
MigrateParam,
RetType,
FieldType,
>
{
type Error = StdError;
Expand Down Expand Up @@ -49,6 +50,7 @@ mod tests {
SvCustomMsg,
SvCustomMsg,
sylvia::types::SvCustomMsg,
String,
_,
>::store_code(&app);

Expand Down
4 changes: 3 additions & 1 deletion examples/contracts/generic_contract/src/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use sylvia::types::{ExecCtx, QueryCtx, SvCustomMsg};
#[contract(module = crate::contract)]
#[messages(generic as Generic)]
#[sv::custom(msg=SvCustomMsg)]
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType>
impl<InstantiateParam, ExecParam, QueryParam, MigrateParam, RetType, FieldType>
Generic<SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg>
for crate::contract::GenericContract<
InstantiateParam,
ExecParam,
QueryParam,
MigrateParam,
RetType,
FieldType,
>
{
type Error = StdError;
Expand Down Expand Up @@ -58,6 +59,7 @@ mod tests {
SvCustomMsg,
SvCustomMsg,
sylvia::types::SvCustomMsg,
String,
_,
> = CodeId::store_code(&app);

Expand Down
4 changes: 4 additions & 0 deletions examples/contracts/generic_iface_on_contract/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ use cosmwasm_std::{Response, StdResult};
use sylvia::types::{InstantiateCtx, SvCustomMsg};
use sylvia::{contract, schemars};

#[cfg(not(feature = "library"))]
use sylvia::entry_points;

pub struct NonGenericContract;

#[cfg_attr(not(feature = "library"), entry_points)]
#[contract]
#[messages(generic<SvCustomMsg, sylvia::types::SvCustomMsg, SvCustomMsg> as Generic: custom(msg))]
#[messages(custom_and_generic<SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg> as CustomAndGeneric)]
Expand Down
2 changes: 1 addition & 1 deletion sylvia-derive/src/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Interfaces {
quote! {}
};

let type_name = msg_ty.as_accessor_name();
let type_name = msg_ty.as_accessor_name(false);
quote! {
<#module ::sv::Api #generics as #sylvia ::types::InterfaceApi> :: #type_name :: response_schemas_impl()
}
Expand Down
5 changes: 3 additions & 2 deletions sylvia-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,10 @@ pub fn entry_points(attr: TokenStream, item: TokenStream) -> TokenStream {

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

Ok(quote! {
#input
Expand Down
49 changes: 32 additions & 17 deletions sylvia-derive/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::crate_module;
use crate::interfaces::Interfaces;
use crate::parser::{
parse_associated_custom_type, parse_struct_message, ContractErrorAttr, ContractMessageAttr,
Custom, MsgAttr, MsgType, OverrideEntryPoints,
Custom, EntryPointArgs, MsgAttr, MsgType, OverrideEntryPoints,
};
use crate::strip_generics::StripGenerics;
use crate::utils::{
Expand All @@ -16,11 +16,12 @@ use proc_macro_error::emit_error;
use quote::{quote, ToTokens};
use syn::fold::Fold;
use syn::parse::{Parse, Parser};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::visit::Visit;
use syn::{
parse_quote, Attribute, GenericParam, Ident, ItemImpl, ItemTrait, Pat, PatType, Path,
ReturnType, Signature, TraitItem, Type, WhereClause, WherePredicate,
parse_quote, Attribute, GenericArgument, GenericParam, Ident, ItemImpl, ItemTrait, Pat,
PatType, Path, ReturnType, Signature, Token, TraitItem, Type, WhereClause, WherePredicate,
};

/// Representation of single struct message
Expand Down Expand Up @@ -747,7 +748,7 @@ impl<'a> MsgVariant<'a> {
let bracketed_generics = emit_bracketed_generics(generics);
let interface_enum =
quote! { < #module sv::Api #bracketed_generics as #sylvia ::types::InterfaceApi> };
let type_name = msg_ty.as_accessor_name();
let type_name = msg_ty.as_accessor_name(false);
let name = Ident::new(&name.to_string().to_case(Case::Snake), name.span());

match msg_ty {
Expand Down Expand Up @@ -790,7 +791,7 @@ impl<'a> MsgVariant<'a> {
} = self;

let params = fields.iter().map(|field| field.emit_method_field());
let type_name = msg_ty.as_accessor_name();
let type_name = msg_ty.as_accessor_name(false);
let name = Ident::new(&name.to_string().to_case(Case::Snake), name.span());

match msg_ty {
Expand Down Expand Up @@ -1023,12 +1024,9 @@ where
custom_query: &Type,
name: &Type,
error: &Type,
contract_generics: &Option<Punctuated<GenericArgument, Token![,]>>,
) -> TokenStream {
let Self {
used_generics,
msg_ty,
..
} = self;
let Self { msg_ty, .. } = self;
let sylvia = crate_module();

let resp_type = match msg_ty {
Expand All @@ -1038,16 +1036,19 @@ where
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 msg_name = msg_ty.emit_msg_name(true);
let bracketed_generics = emit_bracketed_generics(used_generics);
let bracketed_generics = match &contract_generics {
Some(generics) => quote! { ::< #generics > },
None => quote! {},
};
let associated_name = msg_ty.as_accessor_name(true);

quote! {
#[#sylvia ::cw_std::entry_point]
pub fn #ep_name (
#params ,
msg: sv:: #msg_name #bracketed_generics,
msg: < #name < #contract_generics > as #sylvia ::types::ContractApi> :: #associated_name,
) -> Result<#resp_type, #error> {
msg.dispatch(&#name ::new() , ( #values )).map_err(Into::into)
msg.dispatch(&#name #bracketed_generics ::new() , ( #values )).map_err(Into::into)
}
}
}
Expand Down Expand Up @@ -1608,10 +1609,11 @@ pub struct EntryPoints<'a> {
override_entry_points: OverrideEntryPoints,
generics: Vec<&'a GenericParam>,
where_clause: &'a Option<WhereClause>,
attrs: EntryPointArgs,
}

impl<'a> EntryPoints<'a> {
pub fn new(source: &'a ItemImpl) -> Self {
pub fn new(source: &'a ItemImpl, attrs: EntryPointArgs) -> Self {
let sylvia = crate_module();
let name = StripGenerics.fold_type(*source.self_ty.clone());
let override_entry_points = OverrideEntryPoints::new(&source.attrs);
Expand Down Expand Up @@ -1643,6 +1645,7 @@ impl<'a> EntryPoints<'a> {
override_entry_points,
generics,
where_clause,
attrs,
}
}

Expand All @@ -1655,6 +1658,7 @@ impl<'a> EntryPoints<'a> {
override_entry_points,
generics,
where_clause,
attrs,
} = self;
let sylvia = crate_module();

Expand Down Expand Up @@ -1683,6 +1687,10 @@ impl<'a> EntryPoints<'a> {
.iter()
.map(|variant| variant.function_name.clone())
.next();
let contract_generics = match &attrs.generics {
Some(generics) => quote! { ::< #generics > },
None => quote! {},
};

#[cfg(not(tarpaulin_include))]
{
Expand All @@ -1696,6 +1704,7 @@ impl<'a> EntryPoints<'a> {
&custom_query,
name,
error,
&attrs.generics,
),
},
);
Expand All @@ -1706,7 +1715,13 @@ impl<'a> EntryPoints<'a> {

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)
migrate_variants.emit_default_entry_point(
&custom_msg,
&custom_query,
name,
error,
&attrs.generics,
)
} else {
quote! {}
};
Expand All @@ -1722,7 +1737,7 @@ impl<'a> EntryPoints<'a> {
env: #sylvia ::cw_std::Env,
msg: #sylvia ::cw_std::Reply,
) -> Result<#sylvia ::cw_std::Response < #custom_msg >, #error> {
#name ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
#name #contract_generics ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
}
},
_ => quote! {},
Expand Down
Loading

0 comments on commit cc11f29

Please sign in to comment.