lib.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. extern crate proc_macro;
  2. use quote::quote;
  3. use syn::parse_macro_input;
  4. /// Executes the given access control method before running the decorated
  5. /// instruction handler. Any method in scope of the attribute can be invoked
  6. /// with any arguments from the associated instruction handler.
  7. ///
  8. /// # Example
  9. ///
  10. /// ```ignore
  11. /// use anchor_lang::prelude::*;
  12. ///
  13. /// #[program]
  14. /// mod errors {
  15. /// use super::*;
  16. ///
  17. /// #[access_control(Create::accounts(&ctx, bump_seed))]
  18. /// pub fn create(ctx: Context<Create>, bump_seed: u8) -> Result<()> {
  19. /// let my_account = &mut ctx.accounts.my_account;
  20. /// my_account.bump_seed = bump_seed;
  21. /// }
  22. /// }
  23. ///
  24. /// #[derive(Accounts)]
  25. /// pub struct Create {
  26. /// #[account(init)]
  27. /// my_account: Account<'info, MyAccount>,
  28. /// }
  29. ///
  30. /// impl Create {
  31. /// pub fn accounts(ctx: &Context<Create>, bump_seed: u8) -> Result<()> {
  32. /// let seeds = &[ctx.accounts.my_account.to_account_info().key.as_ref(), &[bump_seed]];
  33. /// Pubkey::create_program_address(seeds, ctx.program_id)
  34. /// .map_err(|_| ErrorCode::InvalidNonce)?;
  35. /// Ok(())
  36. /// }
  37. /// }
  38. /// ```
  39. ///
  40. /// This example demonstrates a useful pattern. Not only can you use
  41. /// `#[access_control]` to ensure any invariants or preconditions hold prior to
  42. /// executing an instruction, but also it can be used to finish any validation
  43. /// on the `Accounts` struct, particularly when instruction arguments are
  44. /// needed. Here, we use the given `bump_seed` to verify it creates a valid
  45. /// program-derived address.
  46. #[proc_macro_attribute]
  47. pub fn access_control(
  48. args: proc_macro::TokenStream,
  49. input: proc_macro::TokenStream,
  50. ) -> proc_macro::TokenStream {
  51. let mut args = args.to_string();
  52. args.retain(|c| !c.is_whitespace());
  53. let access_control: Vec<proc_macro2::TokenStream> = args
  54. .split(')')
  55. .filter(|ac| !ac.is_empty())
  56. .map(|ac| format!("{})", ac)) // Put back on the split char.
  57. .map(|ac| format!("{}?;", ac)) // Add `?;` syntax.
  58. .map(|ac| ac.parse().unwrap())
  59. .collect();
  60. let item_fn = parse_macro_input!(input as syn::ItemFn);
  61. let fn_attrs = item_fn.attrs;
  62. let fn_vis = item_fn.vis;
  63. let fn_sig = item_fn.sig;
  64. let fn_block = item_fn.block;
  65. let fn_stmts = fn_block.stmts;
  66. proc_macro::TokenStream::from(quote! {
  67. #(#fn_attrs)*
  68. #fn_vis #fn_sig {
  69. #(#access_control)*
  70. #(#fn_stmts)*
  71. }
  72. })
  73. }