utils.rs 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. use anchor_idl::types::Idl;
  2. use quote::{format_ident, quote};
  3. use super::common::gen_discriminator;
  4. pub fn gen_utils_mod(idl: &Idl) -> proc_macro2::TokenStream {
  5. let event = gen_event(idl);
  6. quote! {
  7. /// Program utilities.
  8. pub mod utils {
  9. #event
  10. }
  11. }
  12. }
  13. fn gen_event(idl: &Idl) -> proc_macro2::TokenStream {
  14. let variants = idl
  15. .events
  16. .iter()
  17. .map(|ev| format_ident!("{}", ev.name))
  18. .map(|name| quote! { #name(#name) });
  19. let match_arms = idl.events.iter().map(|ev| {
  20. let disc = gen_discriminator(&ev.discriminator);
  21. let name = format_ident!("{}", ev.name);
  22. let event = quote! {
  23. #name::try_from_slice(&value[8..])
  24. .map(Self::#name)
  25. .map_err(Into::into)
  26. };
  27. quote! { #disc => #event }
  28. });
  29. quote! {
  30. use super::{*, events::*};
  31. /// An enum that includes all events of the declared program as a tuple variant.
  32. ///
  33. /// See [`Self::try_from_bytes`] to create an instance from bytes.
  34. pub enum Event {
  35. #(#variants,)*
  36. }
  37. impl Event {
  38. /// Try to create an event based on the given bytes.
  39. ///
  40. /// This method returns an error if the discriminator of the given bytes don't match
  41. /// with any of the existing events, or if the deserialization fails.
  42. pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
  43. Self::try_from(bytes)
  44. }
  45. }
  46. impl TryFrom<&[u8]> for Event {
  47. type Error = anchor_lang::error::Error;
  48. fn try_from(value: &[u8]) -> Result<Self> {
  49. if value.len() < 8 {
  50. return Err(ProgramError::InvalidArgument.into());
  51. }
  52. match &value[..8] {
  53. #(#match_arms,)*
  54. _ => Err(ProgramError::InvalidArgument.into()),
  55. }
  56. }
  57. }
  58. }
  59. }