exit.rs 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. use crate::accounts_codegen::constraints::OptionalCheckScope;
  2. use crate::codegen::accounts::{generics, ParsedGenerics};
  3. use crate::{AccountField, AccountsStruct, Ty};
  4. use quote::quote;
  5. // Generates the `Exit` trait implementation.
  6. pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
  7. let name = &accs.ident;
  8. let ParsedGenerics {
  9. combined_generics,
  10. trait_generics,
  11. struct_generics,
  12. where_clause,
  13. } = generics(accs);
  14. let on_save: Vec<proc_macro2::TokenStream> = accs
  15. .fields
  16. .iter()
  17. .map(|af: &AccountField| match af {
  18. AccountField::CompositeField(s) => {
  19. let name = &s.ident;
  20. let name_str = name.to_string();
  21. quote! {
  22. anchor_lang::AccountsExit::exit(&self.#name, program_id)
  23. .map_err(|e| e.with_account_name(#name_str))?;
  24. }
  25. }
  26. AccountField::Field(f) => {
  27. let ident = &f.ident;
  28. let name_str = ident.to_string();
  29. if f.constraints.is_close() {
  30. let close_target = &f.constraints.close.as_ref().unwrap().sol_dest;
  31. let close_target_optional_check =
  32. OptionalCheckScope::new(accs).generate_check(close_target);
  33. quote! {
  34. {
  35. let #close_target = &self.#close_target;
  36. #close_target_optional_check
  37. anchor_lang::AccountsClose::close(
  38. &self.#ident,
  39. #close_target.to_account_info(),
  40. ).map_err(|e| e.with_account_name(#name_str))?;
  41. }
  42. }
  43. } else {
  44. match f.constraints.is_mutable() {
  45. false => quote! {},
  46. true => match &f.ty {
  47. // `LazyAccount` is special because it has a custom `exit` method.
  48. Ty::LazyAccount(_) => quote! {
  49. self.#ident.exit(program_id)
  50. .map_err(|e| e.with_account_name(#name_str))?;
  51. },
  52. _ => quote! {
  53. anchor_lang::AccountsExit::exit(&self.#ident, program_id)
  54. .map_err(|e| e.with_account_name(#name_str))?;
  55. },
  56. },
  57. }
  58. }
  59. }
  60. })
  61. .collect();
  62. quote! {
  63. #[automatically_derived]
  64. impl<#combined_generics> anchor_lang::AccountsExit<#trait_generics> for #name<#struct_generics> #where_clause{
  65. fn exit(&self, program_id: &anchor_lang::solana_program::pubkey::Pubkey) -> anchor_lang::Result<()> {
  66. #(#on_save)*
  67. Ok(())
  68. }
  69. }
  70. }
  71. }