typhoon_metadata_extractor/instruction/
account.rs1use {
2 crate::doc::Docs,
3 syn::{Field, GenericArgument, PathArguments, PathSegment, Type},
4};
5
6#[derive(Debug, Default)]
7pub struct AccountFlags {
8 is_signer: bool,
9 is_mutable: bool,
10 is_optional: bool,
11}
12
13#[derive(Debug)]
14pub struct InstructionAccount {
15 pub name: String,
16 pub docs: Docs,
17 pub flags: AccountFlags,
18}
19
20impl From<&Field> for InstructionAccount {
21 fn from(value: &Field) -> Self {
22 let mut flags = AccountFlags::default();
23 extract_account_flags(&value.ty, &mut flags);
24
25 let docs = Docs::from(value.attrs.as_slice());
26
27 let name = value
29 .ident
30 .as_ref()
31 .map(|i| i.to_string())
32 .unwrap_or_default();
33
34 InstructionAccount { name, docs, flags }
35 }
36}
37
38fn extract_ty_segment(ty: &Type) -> Option<&PathSegment> {
39 match ty {
40 Type::Path(ty_path) => ty_path.path.segments.last(),
41 _ => None,
42 }
43}
44
45fn extract_ty_from_arguments(args: &PathArguments) -> Option<&Type> {
46 match args {
47 PathArguments::AngleBracketed(generic_args) => {
48 generic_args.args.first().and_then(|arg| match arg {
49 GenericArgument::Type(ty) => Some(ty),
50 _ => None,
51 })
52 }
53 _ => None,
54 }
55}
56
57fn extract_account_flags(ty: &Type, account_flags: &mut AccountFlags) {
58 if let Some(PathSegment { ident, arguments }) = extract_ty_segment(ty) {
59 let name = ident.to_string();
60 match name.as_str() {
61 "Option" => {
62 if let Some(inner_ty) = extract_ty_from_arguments(arguments) {
63 account_flags.is_optional = true;
64 extract_account_flags(inner_ty, account_flags);
65 }
66 }
67 "Mut" => {
68 if let Some(inner_ty) = extract_ty_from_arguments(arguments) {
69 account_flags.is_mutable = true;
70 extract_account_flags(inner_ty, account_flags);
71 }
72 }
73 "Signer" => account_flags.is_signer = true,
74 _ => (),
75 }
76 }
77}