Skip to content

Commit

Permalink
fix: only update/query macros can take guard function (#418)
Browse files Browse the repository at this point in the history
* fix: only update/query take guard function

* trim docs

* test

* fix doc:wq

* bump ver

* changelog

* fix docs
  • Loading branch information
lwshang authored Jul 27, 2023
1 parent 185f49f commit 779306c
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 85 deletions.
6 changes: 6 additions & 0 deletions src/ic-cdk-macros/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.7.1] - 2023-07-27

### Fixed

- Only update/query macros can take guard function. (#417)

## [0.7.0] - 2023-07-13

### Added
Expand Down
2 changes: 1 addition & 1 deletion src/ic-cdk-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ic-cdk-macros"
version = "0.7.0" # no need to sync with ic-cdk
version = "0.7.1" # no need to sync with ic-cdk
authors.workspace = true
edition.workspace = true
license.workspace = true
Expand Down
7 changes: 7 additions & 0 deletions src/ic-cdk-macros/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ fn dfn_macro(
};

let guard = if let Some(guard_name) = attrs.guard {
// ic_cdk::api::call::reject calls ic0::msg_reject which is only allowed in update/query
if method.is_lifecycle() {
return Err(Error::new(
attr.span(),
format!("#[{}] cannot have a guard function.", method),
));
}
let guard_ident = syn::Ident::new(&guard_name, Span::call_site());

quote! {
Expand Down
88 changes: 4 additions & 84 deletions src/ic-cdk-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! This crate provide a set of attribute macros to faciliate canister development.
//! This crate provide a set of attribute macros to facilitate canister development.
//!
//! The macros fall into two categories:
//! * To register functions as canister entry points
//! * To import another canister as a rust struct for inter-canister operation.
//! * To export candid definitions
//!
//! ## Register functions as canister entry points
//!
Expand All @@ -16,9 +16,9 @@
//! * [`update`](attr.update.html)
//! * [`query`](attr.query.html)
//!
//! ## Import another canister as a rust struct
//! ## Export candid definitions
//!
//! * [`import`](attr.import.html)
//! * [`export_candid`](attr.export_candid.html)
#![warn(
elided_lifetimes_in_paths,
Expand Down Expand Up @@ -262,22 +262,6 @@ pub fn update(attr: TokenStream, item: TokenStream) -> TokenStream {
/// }
/// ```
///
/// You can specify a guard function to be executed before the init function.
/// When the guard function returns an error, the init function will not proceed.
///
/// ```rust
/// # use ic_cdk::init;
/// fn guard_function() -> Result<(), String> {
/// // ...
/// # unimplemented!()
/// }
/// #[init(guard = "guard_function")]
/// fn init_function() {
/// // ...
/// # unimplemented!()
/// }
/// ```
///
/// The init function may accept an argument, if that argument is a `CandidType`:
///
/// ```rust
Expand Down Expand Up @@ -323,22 +307,6 @@ pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # unimplemented!()
/// }
/// ```
///
/// You can specify a guard function to be executed before the pre_upgrade function.
/// When the guard function returns an error, the pre_upgrade function will not proceed.
///
/// ```rust
/// # use ic_cdk::pre_upgrade;
/// fn guard_function() -> Result<(), String> {
/// // ...
/// # unimplemented!()
/// }
/// #[pre_upgrade(guard = "guard_function")]
/// fn pre_upgrade_function() {
/// // ...
/// # unimplemented!()
/// }
/// ```
#[proc_macro_attribute]
pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
handle_debug_and_errors(export::ic_pre_upgrade, "ic_pre_upgrade", attr, item)
Expand All @@ -363,22 +331,6 @@ pub fn pre_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # unimplemented!()
/// }
/// ```
///
/// You can specify a guard function to be executed before the post_upgrade function.
/// When the guard function returns an error, the post_upgrade function will not proceed.
///
/// ```rust
/// # use ic_cdk::post_upgrade;
/// fn guard_function() -> Result<(), String> {
/// // ...
/// # unimplemented!()
/// }
/// #[post_upgrade(guard = "guard_function")]
/// fn post_upgrade_function() {
/// // ...
/// # unimplemented!()
/// }
/// ```
#[proc_macro_attribute]
pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
handle_debug_and_errors(export::ic_post_upgrade, "ic_post_upgrade", attr, item)
Expand All @@ -403,22 +355,6 @@ pub fn post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # unimplemented!()
/// }
/// ```
///
/// You can specify a guard function to be executed before the heartbeat function.
/// When the guard function returns an error, the heartbeat function will not proceed.
///
/// ```rust
/// # use ic_cdk::heartbeat;
/// fn guard_function() -> Result<(), String> {
/// // ...
/// # unimplemented!()
/// }
/// #[heartbeat(guard = "guard_function")]
/// fn heartbeat_function() {
/// // ...
/// # unimplemented!()
/// }
/// ```
#[proc_macro_attribute]
pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream {
handle_debug_and_errors(export::ic_heartbeat, "ic_heartbeat", attr, item)
Expand All @@ -443,22 +379,6 @@ pub fn heartbeat(attr: TokenStream, item: TokenStream) -> TokenStream {
/// # unimplemented!()
/// }
/// ```
///
/// You can specify a guard function to be executed before the inspect_message function.
/// When the guard function returns an error, the inspect_message function will not proceed.
///
/// ```rust
/// # use ic_cdk::*;
/// fn guard_function() -> Result<(), String> {
/// // ...
/// # unimplemented!()
/// }
/// #[inspect_message(guard = "guard_function")]
/// fn inspect_message_function() {
/// // ...
/// # unimplemented!()
/// }
/// ```
#[proc_macro_attribute]
pub fn inspect_message(attr: TokenStream, item: TokenStream) -> TokenStream {
handle_debug_and_errors(export::ic_inspect_message, "ic_inspect_message", attr, item)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use ic_cdk::{heartbeat, init, inspect_message, post_upgrade, pre_upgrade};

fn guard_function() -> Result<(), String> {
unimplemented!()
}

#[init(guard = "guard_function")]
fn init() {}

#[pre_upgrade(guard = "guard_function")]
fn pre_upgrade() {}

#[post_upgrade(guard = "guard_function")]
fn post_upgrade() {}

#[heartbeat(guard = "guard_function")]
fn heartbeat() {}

#[inspect_message(guard = "guard_function")]
fn inspect_message() {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error: #[init] cannot have a guard function.
--> tests/compile_fail/no_guard_function_for_lifecycle.rs:7:8
|
7 | #[init(guard = "guard_function")]
| ^^^^^

error: #[pre_upgrade] cannot have a guard function.
--> tests/compile_fail/no_guard_function_for_lifecycle.rs:10:15
|
10 | #[pre_upgrade(guard = "guard_function")]
| ^^^^^

error: #[post_upgrade] cannot have a guard function.
--> tests/compile_fail/no_guard_function_for_lifecycle.rs:13:16
|
13 | #[post_upgrade(guard = "guard_function")]
| ^^^^^

error: #[heartbeat] cannot have a guard function.
--> tests/compile_fail/no_guard_function_for_lifecycle.rs:16:13
|
16 | #[heartbeat(guard = "guard_function")]
| ^^^^^

error: #[inspect_message] cannot have a guard function.
--> tests/compile_fail/no_guard_function_for_lifecycle.rs:19:19
|
19 | #[inspect_message(guard = "guard_function")]
| ^^^^^

0 comments on commit 779306c

Please sign in to comment.