Skip to content

Commit

Permalink
idl instruction: add create account macro attr
Browse files Browse the repository at this point in the history
  • Loading branch information
ngundotra committed Oct 31, 2022
1 parent a5bd471 commit 3689780
Show file tree
Hide file tree
Showing 13 changed files with 80 additions and 78 deletions.
17 changes: 17 additions & 0 deletions shank-idl/tests/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ fn instruction_from_single_file_with_multiple_args() {
assert_eq!(idl, expected_idl);
}

#[test]
fn instruction_from_single_file_with_idl_instructions() {
let file = fixtures_dir()
.join("single_file")
.join("create_idl_instructions.rs");
let idl = parse_file(&file, &ParseIdlConfig::optional_program_address())
.expect("Parsing should not fail")
.expect("File contains IDL");

let expected_idl: Idl = serde_json::from_str(include_str!(
"./fixtures/instructions/single_file/create_idl_instructions.json"
))
.unwrap();

assert_eq!(idl, expected_idl);
}

#[test]
fn instruction_from_single_file_with_optional_account() {
let file = fixtures_dir()
Expand Down
2 changes: 1 addition & 1 deletion shank-macro-impl/src/converters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ use syn::Error as ParseError;
pub fn parse_error_into<T: Into<ParseError>>(parse_err: T) -> Error {
let parse_err: ParseError = parse_err.into();
Error::new(parse_err)
.context(format!("[ParseError] Run `cargo build` or `cargo check` in the program crate root for more details."))
.context("[ParseError] Run `cargo build` or `cargo check` in the program crate root for more details.".to_string())
}
2 changes: 1 addition & 1 deletion shank-macro-impl/src/custom_type/custom_type_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ impl DetectCustomTypeConfig {
saw_include = self.include_derives.contains(&derive);
}
}
return saw_include;
saw_include
}
}
7 changes: 3 additions & 4 deletions shank-macro-impl/src/error/program_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl ProgramError {
|x| x.clone(),
);
Self::parse_account_error_args(
&nested,
nested,
&ident,
variant_ident,
variant_discriminant,
Expand Down Expand Up @@ -101,8 +101,7 @@ impl TryFrom<&ParsedEnum> for ProgramErrors {
.collect::<ParseResult<Vec<Option<ProgramError>>>>()?;
let program_errors = program_errors
.into_iter()
.filter(Option::is_some)
.map(Option::unwrap)
.flatten()
.collect::<Vec<ProgramError>>();

Ok(ProgramErrors(program_errors))
Expand Down Expand Up @@ -130,7 +129,7 @@ impl ProgramError {
"shank expects no more than one #[error]s per variant",
))
} else {
Ok(program_errors.to_owned().first().map(|x| x.clone()))
Ok(program_errors.first().cloned())
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions shank-macro-impl/src/error/this_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ pub fn extract_this_errors<'a>(
.iter()
.map(ProgramErrors::try_from)
.collect::<ParseResult<Vec<ProgramErrors>>>()?
.into_iter()
.map(|x| x.0)
.flatten()
.into_iter().flat_map(|x| x.0)
.collect::<Vec<ProgramError>>();
Ok(program_errors)
}
53 changes: 22 additions & 31 deletions shank-macro-impl/src/instruction/account_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::convert::TryFrom;

use proc_macro2::Span;
use syn::{
punctuated::Punctuated, Attribute, Error as ParseError, Ident, Lit, Meta,
MetaList, MetaNameValue, NestedMeta, Result as ParseResult, Token,
punctuated::Punctuated, Attribute, Error as ParseError, Ident, Lit, Meta, MetaList,
MetaNameValue, NestedMeta, Result as ParseResult, Token,
};

const IX_ACCOUNT: &str = "account";
Expand Down Expand Up @@ -34,9 +34,7 @@ impl InstructionAccount {
}
}

pub fn from_account_attr(
attr: &Attribute,
) -> ParseResult<InstructionAccount> {
pub fn from_account_attr(attr: &Attribute) -> ParseResult<InstructionAccount> {
let meta = &attr.parse_meta()?;

match meta {
Expand All @@ -45,7 +43,7 @@ impl InstructionAccount {
|| Ident::new("attr_ident", Span::call_site()),
|x| x.clone(),
);
Self::parse_account_attr_args(ident, &nested)
Self::parse_account_attr_args(ident, nested)
}
Meta::Path(_) | Meta::NameValue(_) => Err(ParseError::new_spanned(
attr,
Expand Down Expand Up @@ -73,9 +71,7 @@ impl InstructionAccount {
let mut optional = false;

for meta in nested {
if let Some((ident, name, value)) =
string_assign_from_nested_meta(meta)?
{
if let Some((ident, name, value)) = string_assign_from_nested_meta(meta)? {
// name/desc
match name.as_str() {
"desc" | "description" => desc = Some(value),
Expand All @@ -86,14 +82,14 @@ impl InstructionAccount {
))
}
"name" => account_name = Some(value),
_ => return Err(ParseError::new_spanned(
ident,
"Only desc/description or name can be assigned strings",
)),
_ => {
return Err(ParseError::new_spanned(
ident,
"Only desc/description or name can be assigned strings",
))
}
};
} else if let Some((ident, name)) =
identifier_from_nested_meta(meta)
{
} else if let Some((ident, name)) = identifier_from_nested_meta(meta) {
// signer, writable, optional ...
match name.as_str() {
"signer" | "sign" | "sig" | "s" => signer = true,
Expand Down Expand Up @@ -133,9 +129,7 @@ impl InstructionAccount {
desc,
optional,
}),
None => {
Err(ParseError::new_spanned(nested, "Missing account name"))
}
None => Err(ParseError::new_spanned(nested, "Missing account name")),
}
}
}
Expand All @@ -145,7 +139,7 @@ impl TryFrom<&[Attribute]> for InstructionAccounts {

fn try_from(attrs: &[Attribute]) -> ParseResult<Self> {
let accounts = attrs
.into_iter()
.iter()
.filter_map(InstructionAccount::is_account_attr)
.map(InstructionAccount::from_account_attr)
.collect::<ParseResult<Vec<InstructionAccount>>>()?;
Expand Down Expand Up @@ -176,14 +170,15 @@ fn string_assign_from_nested_meta(
nested_meta: &NestedMeta,
) -> ParseResult<Option<(Ident, String, String)>> {
match nested_meta {
NestedMeta::Meta(Meta::NameValue(MetaNameValue {
path, lit, ..
})) => {
NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) => {
let ident = path.get_ident();
if let Some(ident) = ident {
let token = match lit {
let token = match lit {
Lit::Str(lit) => Ok(lit.value()),
_ => Err(ParseError::new_spanned(ident, "#[account(desc)] arg needs to be assigning to a string")),
_ => Err(ParseError::new_spanned(
ident,
"#[account(desc)] arg needs to be assigning to a string",
)),
}?;
Ok(Some((ident.clone(), ident.to_string(), token)))
} else {
Expand All @@ -194,14 +189,10 @@ fn string_assign_from_nested_meta(
}
}

fn identifier_from_nested_meta(
nested_meta: &NestedMeta,
) -> Option<(Ident, String)> {
pub fn identifier_from_nested_meta(nested_meta: &NestedMeta) -> Option<(Ident, String)> {
match nested_meta {
NestedMeta::Meta(meta) => match meta {
Meta::Path(_) => {
meta.path().get_ident().map(|x| (x.clone(), x.to_string()))
}
Meta::Path(_) => meta.path().get_ident().map(|x| (x.clone(), x.to_string())),
// ignore named values and lists
_ => None,
},
Expand Down
8 changes: 4 additions & 4 deletions shank-macro-impl/src/instruction/account_attrs_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl From<&InstructionAccount> for InstructionAccountWithoutIdent {
writable: *writable,
signer: *signer,
desc: desc.clone(),
optional: optional.clone(),
optional: *optional,
}
}
}
Expand Down Expand Up @@ -320,10 +320,10 @@ fn account_multiple_attrs() {
InstructionAccountWithoutIdent {
index: None,
name: name.clone(),
writable: writable.clone(),
signer: signer.clone(),
writable: *writable,
signer: *signer,
desc: desc.clone(),
optional: optional.clone(),
optional: *optional,
}
},
)
Expand Down
30 changes: 17 additions & 13 deletions shank-macro-impl/src/instruction/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
};

use super::account_attrs::{InstructionAccount, InstructionAccounts};
use super::IdlInstruction;

// -----------------
// Instruction
Expand All @@ -27,8 +28,7 @@ impl Instruction {
skip_derive_attr_check: bool,
) -> ParseResult<Option<Instruction>> {
if skip_derive_attr_check
|| get_derive_attr(&item_enum.attrs, DERIVE_INSTRUCTION_ATTR)
.is_some()
|| get_derive_attr(&item_enum.attrs, DERIVE_INSTRUCTION_ATTR).is_some()
{
let parsed_enum = ParsedEnum::try_from(item_enum)?;
Instruction::try_from(&parsed_enum).map(Some)
Expand All @@ -42,9 +42,7 @@ impl TryFrom<&ParsedEnum> for Option<Instruction> {
type Error = ParseError;

fn try_from(parsed_enum: &ParsedEnum) -> ParseResult<Self> {
match get_derive_attr(&parsed_enum.attrs, DERIVE_INSTRUCTION_ATTR)
.map(|_| parsed_enum)
{
match get_derive_attr(&parsed_enum.attrs, DERIVE_INSTRUCTION_ATTR).map(|_| parsed_enum) {
Some(ix_enum) => ix_enum.try_into().map(Some),
None => Ok(None),
}
Expand Down Expand Up @@ -99,19 +97,14 @@ impl TryFrom<&ParsedEnumVariant> for InstructionVariant {
..
} = variant;

let field_tys: InstructionVariantFields = if fields.len() > 0 {
let mut field_tys: InstructionVariantFields = if !fields.is_empty() {
// Determine if the InstructionType is tuple or struct variant
let field = fields.get(0).unwrap();
match &field.ident {
Some(_) => InstructionVariantFields::Named(
fields
.iter()
.map(|x| {
(
x.ident.as_ref().unwrap().to_string(),
x.rust_type.clone(),
)
})
.map(|x| (x.ident.as_ref().unwrap().to_string(), x.rust_type.clone()))
.collect(),
),
None => InstructionVariantFields::Unnamed(
Expand All @@ -123,7 +116,18 @@ impl TryFrom<&ParsedEnumVariant> for InstructionVariant {
};

let attrs: &[Attribute] = attrs.as_ref();
let accounts: InstructionAccounts = attrs.try_into()?;
let accounts: InstructionAccounts;

let idl_instruction = IdlInstruction::try_from(attrs);
if idl_instruction.is_ok() {
let idl_ix = idl_instruction.unwrap();
accounts = idl_ix.to_accounts(ident.clone());
field_tys = idl_ix.to_instruction_fields(ident.clone());
} else {
let err = idl_instruction.unwrap_err();
println!("{}", err);
accounts = attrs.try_into()?;
}

Ok(Self {
ident: ident.clone(),
Expand Down
2 changes: 2 additions & 0 deletions shank-macro-impl/src/instruction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod account_attrs;
mod extract_instructions;
mod idl_instruction_attrs;
mod instruction;

pub use account_attrs::*;
pub use extract_instructions::*;
pub use idl_instruction_attrs::*;
pub use instruction::*;

#[cfg(test)]
Expand Down
6 changes: 2 additions & 4 deletions shank-macro-impl/src/macros/program_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ impl TryFrom<&[ItemMacro]> for ProgramId {
literal,
path_idents,
}| {
literal
.map(|lit| {
literal.and_then(|lit| {
if path.ends_with("declare_id") {
Some((path_idents[0].clone(), lit.clone()))
Some((path_idents[0].clone(), lit))
} else {
None
}
})
.flatten()
},
)
.collect();
Expand Down
8 changes: 2 additions & 6 deletions shank-macro-impl/src/parsers/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ fn flattened_idents_from_nested_meta(
nested: &Punctuated<NestedMeta, Token![,]>,
) -> Vec<Ident> {
nested
.iter()
.map(|nested| match nested {
.iter().flat_map(|nested| match nested {
NestedMeta::Meta(Meta::Path(path)) => {
path.segments.iter().map(|x| x.ident.clone()).collect()
}
Expand All @@ -17,14 +16,12 @@ fn flattened_idents_from_nested_meta(
}
_ => vec![],
})
.flatten()
.collect()
}

pub fn get_derive_names(attrs: &[Attribute]) -> Vec<String> {
attrs
.iter()
.map(|attr| {
.iter().flat_map(|attr| {
let meta = &attr.parse_meta();
match meta {
Ok(Meta::List(MetaList { path, nested, .. })) => {
Expand All @@ -46,7 +43,6 @@ pub fn get_derive_names(attrs: &[Attribute]) -> Vec<String> {
Err(_) => vec![],
}
})
.flatten()
.collect()
}

Expand Down
9 changes: 3 additions & 6 deletions shank-macro-impl/src/types/parsed_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@ impl From<&TypeReference> for ParsedReference {
..
} = r;

let lifetime_ident = match lifetime {
Some(Lifetime { ident, .. }) => Some(ident.clone()),
None => None,
};
let lifetime_ident = lifetime.as_ref().map(|Lifetime { ident, .. }| ident.clone());

match mutability.is_some() {
true => ParsedReference::RefMut(lifetime_ident.clone()),
false => ParsedReference::Ref(lifetime_ident.clone()),
true => ParsedReference::RefMut(lifetime_ident),
false => ParsedReference::Ref(lifetime_ident),
}
}
}
Expand Down
Loading

0 comments on commit 3689780

Please sign in to comment.