Skip to content

Commit

Permalink
feat: Allow devs to assign version to a constant
Browse files Browse the repository at this point in the history
  • Loading branch information
kulikthebird committed Sep 2, 2024
1 parent d18766a commit bb79d14
Showing 1 changed file with 93 additions and 9 deletions.
102 changes: 93 additions & 9 deletions packages/derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use syn::spanned::Spanned;
use syn::{
parse::{Parse, ParseStream},
parse_quote,
Expand Down Expand Up @@ -111,6 +112,23 @@ impl Parse for Options {
/// todo!();
/// }
/// ```
///
/// It is also possible to assign the migrate version number to
/// a given constant name:
///
/// ```
/// # use cosmwasm_std::{
/// # DepsMut, entry_point, Env,
/// # Response, StdResult,
/// # };
/// #
/// # type MigrateMsg = ();
/// #[entry_point]
/// #[migrate_version(CONTRACT_VERSION = 2)]
/// pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> StdResult<Response> {
/// todo!();
/// }
/// ```
#[proc_macro_attribute]
pub fn entry_point(
attr: proc_macro::TokenStream,
Expand All @@ -135,7 +153,35 @@ fn expand_attributes(func: &mut ItemFn) -> syn::Result<TokenStream> {
));
}

let version: syn::LitInt = attribute.parse_args()?;
let (const_name, version): (Option<syn::Path>, syn::LitInt) =
match attribute.parse_args()? {
syn::Expr::Assign(syn::ExprAssign { left, right, .. }) => match (*left, *right) {
(
syn::Expr::Path(syn::ExprPath { path, .. }),
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Int(version),
..
}),
) => (Some(path), version),
_ => {
return Err(syn::Error::new(
attribute.span(),
"Expected version number or `CONST_NAME = {version_number}`",
))
}
},
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Int(version),
..
}) => (None, version),
_ => {
return Err(syn::Error::new(
attribute.span(),
"Expected version number or `CONST_NAME = {version_number}`",
))
}
};

// Enforce that the version is a valid u64 and non-zero
let numeric_version = version.base10_parse::<u64>()?;
if numeric_version == 0 {
Expand All @@ -144,6 +190,15 @@ fn expand_attributes(func: &mut ItemFn) -> syn::Result<TokenStream> {
"please start versioning with 1",
));
}
let const_assignment = if let Some(const_name) = const_name {
quote! {
#[allow(unused)]
#[doc(hidden)]
pub const #const_name: u64 = #numeric_version;
}
} else {
quote! {}
};

let version = version.base10_digits();
let n = version.len();
Expand All @@ -160,11 +215,7 @@ fn expand_attributes(func: &mut ItemFn) -> syn::Result<TokenStream> {
/// The format and even the existence of this value is an implementation detail, DO NOT RELY ON THIS!
static __CW_MIGRATE_VERSION: [u8; #n] = *#version;

#[allow(unused)]
#[doc(hidden)]
const fn migrate_version() -> u64 {
#numeric_version
}
#const_assignment
};
}

Expand Down Expand Up @@ -284,11 +335,44 @@ mod test {
/// The format and even the existence of this value is an implementation detail, DO NOT RELY ON THIS!
static __CW_MIGRATE_VERSION: [u8; 1usize] = *b"2";

fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Response {
// Logic here
}

#[cfg(target_arch = "wasm32")]
mod __wasm_export_migrate {
#[no_mangle]
extern "C" fn migrate(ptr_0: u32, ptr_1: u32) -> u32 {
::cosmwasm_std::do_migrate(&super::migrate, ptr_0, ptr_1)
}
}
};

assert_eq!(actual.to_string(), expected.to_string());
}

#[test]
fn contract_migrate_version_with_const_expansion() {
let code = quote! {
#[migrate_version(CONTRACT_VERSION = 66)]
fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Response {
// Logic here
}
};

let actual = entry_point_impl(TokenStream::new(), code);
let expected = quote! {
#[allow(unused)]
#[doc(hidden)]
const fn migrate_version() -> u64 {
2u64
}
#[cfg(target_arch = "wasm32")]
#[link_section = "cw_migrate_version"]
/// This is an internal constant exported as a custom section denoting the contract migrate version.
/// The format and even the existence of this value is an implementation detail, DO NOT RELY ON THIS!
static __CW_MIGRATE_VERSION: [u8; 2usize] = *b"66";

#[allow(unused)]
#[doc(hidden)]
pub const CONTRACT_VERSION: u64 = 66u64;

fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Response {
// Logic here
Expand Down

0 comments on commit bb79d14

Please sign in to comment.