Skip to content

Commit

Permalink
feat: Add support for sv::features attribute. (#446)
Browse files Browse the repository at this point in the history
Remove `sv_replies` feature as it does not make the change non breaking.
  • Loading branch information
jawoznia committed Oct 16, 2024
1 parent d43909d commit c2aebe4
Show file tree
Hide file tree
Showing 21 changed files with 135 additions and 47 deletions.
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ version = "0.5.0"
edition = "2021"

[workspace.dependencies]
sylvia = { path = "../sylvia", features = ["sv_replies"] }
sylvia = { path = "../sylvia" }
cw-storage-plus = "2.0.0"
cw-utils = "2.0.0"
cw2 = "2.0.0"
Expand Down
1 change: 1 addition & 0 deletions examples/contracts/generic_contract/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub struct GenericContract<
#[sv::messages(generic as Generic: custom(msg, query))]
#[sv::messages(custom_and_generic as CustomAndGeneric)]
#[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
#[sv::features(replies)]
impl<
InstantiateT,
Exec1T,
Expand Down
1 change: 1 addition & 0 deletions examples/contracts/generics_forwarded/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct GenericsForwardedContract<
#[sv::messages(cw1 as Cw1: custom(msg, query))]
#[sv::messages(custom_and_generic as CustomAndGeneric)]
#[sv::custom(msg=CustomMsgT, query=CustomQueryT)]
#[sv::features(replies)]
impl<
InstantiateT,
Exec1T,
Expand Down
2 changes: 0 additions & 2 deletions sylvia-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ readme = "../README.md"
[features]
mt = []
cosmwasm_1_2 = []
sv_replies = []

[lib]
proc-macro = true
Expand Down Expand Up @@ -43,7 +42,6 @@ sylvia = { path = "../sylvia", features = [
"cosmwasm_1_2",
"cosmwasm_1_3",
"cosmwasm_1_4",
"sv_replies",
] }
serde = { workspace = true }
cosmwasm-schema = { workspace = true }
Expand Down
6 changes: 5 additions & 1 deletion sylvia-derive/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use proc_macro2::TokenStream;
use quote::quote;
use syn::{GenericParam, ItemImpl};

use crate::parser::attributes::features::SylviaFeatures;
use crate::parser::attributes::msg::MsgType;
use crate::parser::variant_descs::AsVariantDescs;
use crate::parser::{
Expand Down Expand Up @@ -46,6 +47,7 @@ pub struct ContractInput<'a> {
custom: Custom,
override_entry_points: Vec<OverrideEntryPoint>,
interfaces: Interfaces,
sv_features: SylviaFeatures,
}

impl<'a> ContractInput<'a> {
Expand All @@ -56,6 +58,7 @@ impl<'a> ContractInput<'a> {
let parsed_attrs = ParsedSylviaAttributes::new(item.attrs.iter());
let error = parsed_attrs.error_attrs.unwrap_or_default();
let custom = parsed_attrs.custom_attr.unwrap_or_default();
let sv_features = parsed_attrs.sv_features;
let override_entry_points = parsed_attrs.override_entry_point_attrs;
let interfaces = Interfaces::new(item);

Expand All @@ -66,6 +69,7 @@ impl<'a> ContractInput<'a> {
custom,
override_entry_points,
interfaces,
sv_features,
}
}

Expand Down Expand Up @@ -186,7 +190,7 @@ impl<'a> ContractInput<'a> {
}

fn emit_reply(&self) -> TokenStream {
if cfg!(feature = "sv_replies") {
if self.sv_features.replies {
let variants = MsgVariants::new(self.item.as_variants(), MsgType::Reply, &[], &None);

Reply::new(self.item, &self.generics, &variants).emit()
Expand Down
15 changes: 9 additions & 6 deletions sylvia-derive/src/contract/mt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use quote::quote;
use syn::{parse_quote, GenericParam, ItemImpl, Type};

use crate::crate_module;
use crate::parser::attributes::features::SylviaFeatures;
use crate::parser::attributes::msg::MsgType;
use crate::parser::variant_descs::AsVariantDescs;
use crate::parser::{
Expand All @@ -23,6 +24,7 @@ pub struct MtHelpers<'a> {
where_clause: &'a Option<syn::WhereClause>,
custom: &'a Custom,
override_entry_points: Vec<OverrideEntryPoint>,
sv_features: SylviaFeatures,
instantiate_variant: MsgVariants<'a, GenericParam>,
exec_variants: MsgVariants<'a, GenericParam>,
query_variants: MsgVariants<'a, GenericParam>,
Expand Down Expand Up @@ -76,11 +78,10 @@ impl<'a> MtHelpers<'a> {
where_clause,
);

let error_type = ParsedSylviaAttributes::new(source.attrs.iter())
.error_attrs
.unwrap_or_default()
.error;
let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
let error_type = parsed_attrs.error_attrs.unwrap_or_default().error;
let error_type = parse_quote! { #error_type };
let sv_features = parsed_attrs.sv_features;

let contract_name = &source.self_ty;

Expand All @@ -92,6 +93,7 @@ impl<'a> MtHelpers<'a> {
contract_name,
custom,
override_entry_points,
sv_features,
instantiate_variant,
exec_variants,
query_variants,
Expand Down Expand Up @@ -478,6 +480,7 @@ impl<'a> MtHelpers<'a> {
contract_name,
custom,
override_entry_points,
sv_features,
generic_params,
migrate_variants,
reply_variants,
Expand Down Expand Up @@ -529,15 +532,15 @@ impl<'a> MtHelpers<'a> {
quote! { #contract_ident }
};

if cfg!(feature = "sv_replies") {
if sv_features.replies {
quote! {
let contract = #contract_turbofish ::new();
dispatch_reply(deps, env, msg, contract).map_err(Into::into)
}
} else {
let reply_name = _reply.name().to_case(Case::Snake);
quote! {
self. #reply_name ((deps, env).into(), msg).map_err(Into::into)
self. #reply_name ((deps, env, 0, vec![], vec![]).into(), msg).map_err(Into::into)
}
}
})
Expand Down
9 changes: 7 additions & 2 deletions sylvia-derive/src/entry_points.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use syn::{parse_quote, GenericParam, Ident, ItemImpl, Type, WhereClause};

use crate::crate_module;
use crate::fold::StripGenerics;
use crate::parser::attributes::features::SylviaFeatures;
use crate::parser::attributes::msg::MsgType;
use crate::parser::variant_descs::AsVariantDescs;
use crate::parser::{
Expand Down Expand Up @@ -68,13 +69,15 @@ pub struct EntryPoints<'a> {
generics: Vec<&'a GenericParam>,
where_clause: &'a Option<WhereClause>,
attrs: &'a EntryPointArgs,
sv_features: SylviaFeatures,
}

impl<'a> EntryPoints<'a> {
pub fn new(source: &'a ItemImpl, attrs: &'a EntryPointArgs) -> Self {
let name = StripGenerics.fold_type(*source.self_ty.clone());
let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
let override_entry_points = parsed_attrs.override_entry_point_attrs;
let sv_features = parsed_attrs.sv_features;

let error = parsed_attrs.error_attrs.unwrap_or_default().error;

Expand All @@ -96,6 +99,7 @@ impl<'a> EntryPoints<'a> {
generics,
where_clause,
attrs,
sv_features,
}
}

Expand Down Expand Up @@ -172,6 +176,7 @@ impl<'a> EntryPoints<'a> {
error,
attrs,
reply,
sv_features,
..
} = self;
let sylvia = crate_module();
Expand Down Expand Up @@ -201,12 +206,12 @@ impl<'a> EntryPoints<'a> {
_ => quote! { msg: < #contract as #sylvia ::types::ContractApi> :: #associated_name },
};
let dispatch = match msg_ty {
MsgType::Reply if cfg!(feature = "sv_replies") => quote! {
MsgType::Reply if sv_features.replies => quote! {
let contract = #contract_turbofish ::new();
sv::dispatch_reply(deps, env, msg, contract).map_err(Into::into)
},
MsgType::Reply => quote! {
#contract_turbofish ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
#contract_turbofish ::new(). #reply((deps, env, 0, vec![], vec![]).into(), msg).map_err(Into::into)
},
_ => quote! {
msg.dispatch(& #contract_turbofish ::new() , ( #values )).map_err(Into::into)
Expand Down
9 changes: 9 additions & 0 deletions sylvia-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
///
/// ##[sylvia::contract]
/// ##[sv::error(ContractError)]
/// ##[sv::features(replies)]
/// impl SvContract {
/// pub const fn new() -> Self {
/// Self {
Expand Down Expand Up @@ -621,6 +622,13 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
/// and only for message types variants that resolves in an enum field,
/// i.e. `exec`, `query` and `sudo`.
///
/// ### `sv::features(...)`
///
/// Enables additional features for the contract. Allows user to use features that
/// are considered breaking before the major release.
///
/// Currently supported features are:
/// * `replies` - enables better dispatching of `reply` as well as its auto deserialization.
///
#[proc_macro_error]
#[proc_macro_attribute]
Expand Down Expand Up @@ -661,6 +669,7 @@ fn contract_impl(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
///
/// ##[sylvia::entry_points]
/// ##[sylvia::contract]
/// ##[sv::features(replies)]
/// impl SvContract {
/// pub const fn new() -> Self {
/// Self
Expand Down
46 changes: 46 additions & 0 deletions sylvia-derive/src/parser/attributes/features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use proc_macro_error::emit_error;
use syn::parse::{Parse, ParseStream, Parser};
use syn::{Error, Ident, MetaList, Result, Token};

/// Type wrapping data parsed from `sv::features` attribute.
#[derive(Debug, Default)]
pub struct SylviaFeatures {
/// Enables better dispatching and deserialization for replies.
pub replies: bool,
}

impl SylviaFeatures {
pub fn new(attr: &MetaList) -> Result<Self> {
SylviaFeatures::parse
.parse2(attr.tokens.clone())
.map_err(|err| {
emit_error!(err.span(), err);
err
})
}
}

impl Parse for SylviaFeatures {
fn parse(input: ParseStream) -> Result<Self> {
let mut features = Self::default();

while !input.is_empty() {
let feature: Ident = input.parse()?;
match feature.to_string().as_str() {
"replies" => features.replies = true,
_ => {
return Err(Error::new(
feature.span(),
"Invalid feature.\n= note: Expected `#[sv::features(replies)];`.\n",
))
}
}
if !input.peek(Token![,]) {
break;
}
let _: Token![,] = input.parse()?;
}

Ok(features)
}
}
10 changes: 10 additions & 0 deletions sylvia-derive/src/parser/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Module defining parsing of Sylvia attributes.
//! Every Sylvia attribute should be prefixed with `sv::`
use features::SylviaFeatures;
use proc_macro_error::emit_error;
use syn::spanned::Spanned;
use syn::{Attribute, MetaList, PathSegment};

pub mod attr;
pub mod custom;
pub mod error;
pub mod features;
pub mod messages;
pub mod msg;
pub mod override_entry_point;
Expand All @@ -31,6 +33,7 @@ pub enum SylviaAttribute {
VariantAttrs,
MsgAttrs,
Payload,
Features,
}

impl SylviaAttribute {
Expand All @@ -53,6 +56,7 @@ impl SylviaAttribute {
"attr" => Some(Self::VariantAttrs),
"msg_attr" => Some(Self::MsgAttrs),
"payload" => Some(Self::Payload),
"features" => Some(Self::Features),
_ => None,
}
}
Expand All @@ -69,6 +73,7 @@ pub struct ParsedSylviaAttributes {
pub override_entry_point_attrs: Vec<OverrideEntryPoint>,
pub variant_attrs_forward: Vec<VariantAttrForwarding>,
pub msg_attrs_forward: Vec<MsgAttrForwarding>,
pub sv_features: SylviaFeatures,
}

impl ParsedSylviaAttributes {
Expand Down Expand Up @@ -167,6 +172,11 @@ impl ParsedSylviaAttributes {
note = attr.span() => "The `sv::payload` should be used as a prefix for `Binary` payload.";
);
}
SylviaAttribute::Features => {
if let Ok(features) = SylviaFeatures::new(attr) {
self.sv_features = features;
}
}
}
}
}
2 changes: 0 additions & 2 deletions sylvia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ cosmwasm_2_0 = [
"cw-multi-test/cosmwasm_2_0",
"cosmwasm_1_4",
]
# Enables better replies
sv_replies = ["sylvia-derive/sv_replies"]

[dependencies]
sylvia-derive = { workspace = true }
Expand Down
Loading

0 comments on commit c2aebe4

Please sign in to comment.