id.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //! Copied from solana/sdk/macro so that Anchor programs don't need to specify
  2. //! `solana_program` as an additional crate dependency, but instead can access
  3. //! it via `anchor_lang::declare_id`.
  4. //!
  5. //! Convenience macro to declare a static public key and functions to interact with it
  6. //!
  7. //! Input: a single literal base58 string representation of a program's id
  8. extern crate proc_macro;
  9. use proc_macro2::Span;
  10. use quote::{quote, ToTokens};
  11. use syn::{
  12. parse::{Parse, ParseStream, Result},
  13. Expr, LitByte, LitStr,
  14. };
  15. fn parse_id(
  16. input: ParseStream,
  17. pubkey_type: proc_macro2::TokenStream,
  18. ) -> Result<proc_macro2::TokenStream> {
  19. let id = if input.peek(syn::LitStr) {
  20. let id_literal: LitStr = input.parse()?;
  21. parse_pubkey(&id_literal, &pubkey_type)?
  22. } else {
  23. let expr: Expr = input.parse()?;
  24. quote! { #expr }
  25. };
  26. if !input.is_empty() {
  27. let stream: proc_macro2::TokenStream = input.parse()?;
  28. return Err(syn::Error::new_spanned(stream, "unexpected token"));
  29. }
  30. Ok(id)
  31. }
  32. fn id_to_tokens(
  33. id: &proc_macro2::TokenStream,
  34. pubkey_type: proc_macro2::TokenStream,
  35. tokens: &mut proc_macro2::TokenStream,
  36. ) {
  37. tokens.extend(quote! {
  38. /// The static program ID
  39. pub static ID: #pubkey_type = #id;
  40. /// Const version of `ID`
  41. pub const ID_CONST: #pubkey_type = #id;
  42. /// Confirms that a given pubkey is equivalent to the program ID
  43. pub fn check_id(id: &#pubkey_type) -> bool {
  44. id == &ID
  45. }
  46. /// Returns the program ID
  47. pub fn id() -> #pubkey_type {
  48. ID
  49. }
  50. /// Const version of `ID`
  51. pub const fn id_const() -> #pubkey_type {
  52. ID_CONST
  53. }
  54. #[cfg(test)]
  55. #[test]
  56. fn test_id() {
  57. assert!(check_id(&id()));
  58. }
  59. });
  60. }
  61. pub struct Pubkey(proc_macro2::TokenStream);
  62. impl Parse for Pubkey {
  63. fn parse(input: ParseStream) -> Result<Self> {
  64. parse_id(
  65. input,
  66. quote! { anchor_lang::solana_program::pubkey::Pubkey },
  67. )
  68. .map(Self)
  69. }
  70. }
  71. impl ToTokens for Pubkey {
  72. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
  73. let id = &self.0;
  74. tokens.extend(quote! {#id})
  75. }
  76. }
  77. pub struct Id(proc_macro2::TokenStream);
  78. impl Parse for Id {
  79. fn parse(input: ParseStream) -> Result<Self> {
  80. parse_id(
  81. input,
  82. quote! { anchor_lang::solana_program::pubkey::Pubkey },
  83. )
  84. .map(Self)
  85. }
  86. }
  87. impl ToTokens for Id {
  88. fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
  89. id_to_tokens(
  90. &self.0,
  91. quote! { anchor_lang::solana_program::pubkey::Pubkey },
  92. tokens,
  93. )
  94. }
  95. }
  96. fn parse_pubkey(
  97. id_literal: &LitStr,
  98. pubkey_type: &proc_macro2::TokenStream,
  99. ) -> Result<proc_macro2::TokenStream> {
  100. let id_vec = bs58::decode(id_literal.value())
  101. .into_vec()
  102. .map_err(|_| syn::Error::new_spanned(id_literal, "failed to decode base58 string"))?;
  103. let id_array = <[u8; 32]>::try_from(<&[u8]>::clone(&&id_vec[..])).map_err(|_| {
  104. syn::Error::new_spanned(
  105. id_literal,
  106. format!("pubkey array is not 32 bytes long: len={}", id_vec.len()),
  107. )
  108. })?;
  109. let bytes = id_array.iter().map(|b| LitByte::new(*b, Span::call_site()));
  110. Ok(quote! {
  111. #pubkey_type::new_from_array(
  112. [#(#bytes,)*]
  113. )
  114. })
  115. }