Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lang: Parse #[account] attribute arguments with syn #3140

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Make discriminator type unsized ([#3098](https://github.com/coral-xyz/anchor/pull/3098)).
- lang: Require `Discriminator` trait impl when using the `zero` constraint ([#3118](https://github.com/coral-xyz/anchor/pull/3118)).
- ts: Remove `DISCRIMINATOR_SIZE` constant ([#3120](https://github.com/coral-xyz/anchor/pull/3120)).
- lang: `#[account]` attribute arguments no longer parses identifiers as namespaces ([#3140](https://github.com/coral-xyz/anchor/pull/3140)).

## [0.30.1] - 2024-06-20

Expand Down
105 changes: 78 additions & 27 deletions lang/attribute/account/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
extern crate proc_macro;

use quote::quote;
use syn::parse_macro_input;
use quote::{quote, ToTokens};
use syn::{
parenthesized,
parse::{Parse, ParseStream},
parse_macro_input,
token::{Comma, Paren},
Ident, LitStr,
};

mod id;

Expand Down Expand Up @@ -67,31 +73,10 @@ pub fn account(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let mut namespace = "".to_string();
let mut is_zero_copy = false;
let mut unsafe_bytemuck = false;
let args_str = args.to_string();
let args: Vec<&str> = args_str.split(',').collect();
if args.len() > 2 {
panic!("Only two args are allowed to the account attribute.")
}
for arg in args {
let ns = arg
.to_string()
.replace('\"', "")
.chars()
.filter(|c| !c.is_whitespace())
.collect();
if ns == "zero_copy" {
is_zero_copy = true;
unsafe_bytemuck = false;
} else if ns == "zero_copy(unsafe)" {
is_zero_copy = true;
unsafe_bytemuck = true;
} else {
namespace = ns;
}
}
let args = parse_macro_input!(args as AccountArgs);
let namespace = args.namespace.unwrap_or_default();
let is_zero_copy = args.zero_copy.is_some();
let unsafe_bytemuck = args.zero_copy.unwrap_or_default();

let account_strct = parse_macro_input!(input as syn::ItemStruct);
let account_name = &account_strct.ident;
Expand Down Expand Up @@ -248,6 +233,72 @@ pub fn account(
})
}

#[derive(Debug, Default)]
struct AccountArgs {
/// `bool` is for deciding whether to use `unsafe` e.g. `Some(true)` for `zero_copy(unsafe)`
zero_copy: Option<bool>,
namespace: Option<String>,
}

impl Parse for AccountArgs {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut parsed = Self::default();
let args = input.parse_terminated::<_, Comma>(AccountArg::parse)?;
for arg in args {
match arg {
AccountArg::ZeroCopy { is_unsafe } => {
parsed.zero_copy.replace(is_unsafe);
}
AccountArg::Namespace(ns) => {
parsed.namespace.replace(ns);
}
}
}

Ok(parsed)
}
}

enum AccountArg {
ZeroCopy { is_unsafe: bool },
Namespace(String),
}

impl Parse for AccountArg {
fn parse(input: ParseStream) -> syn::Result<Self> {
// Namespace
if let Ok(ns) = input.parse::<LitStr>() {
return Ok(Self::Namespace(
ns.to_token_stream().to_string().replace('\"', ""),
));
}

// Zero copy
let ident = input.parse::<Ident>()?;
if ident == "zero_copy" {
let is_unsafe = if input.peek(Paren) {
let content;
parenthesized!(content in input);
let content = content.parse::<proc_macro2::TokenStream>()?;
if content.to_string().as_str().trim() != "unsafe" {
return Err(syn::Error::new(
syn::spanned::Spanned::span(&content),
"Expected `unsafe`",
));
}

true
} else {
false
};

return Ok(Self::ZeroCopy { is_unsafe });
};

Err(syn::Error::new(ident.span(), "Unexpected argument"))
}
}

#[proc_macro_derive(ZeroCopyAccessor, attributes(accessor))]
pub fn derive_zero_copy_accessor(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let account_strct = parse_macro_input!(item as syn::ItemStruct);
Expand Down
Loading