lib.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  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: ProgramAccount<'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_map(|ac| match ac {
  56. "" => None,
  57. _ => Some(ac),
  58. })
  59. .map(|ac| format!("{})", ac)) // Put back on the split char.
  60. .map(|ac| format!("{}?;", ac)) // Add `?;` syntax.
  61. .map(|ac| ac.parse().unwrap())
  62. .collect();
  63. let item_fn = parse_macro_input!(input as syn::ItemFn);
  64. let fn_vis = item_fn.vis;
  65. let fn_sig = item_fn.sig;
  66. let fn_block = item_fn.block;
  67. let fn_stmts = fn_block.stmts;
  68. proc_macro::TokenStream::from(quote! {
  69. #fn_vis #fn_sig {
  70. #(#access_control)*
  71. #(#fn_stmts)*
  72. }
  73. })
  74. }