typhoon_metadata_extractor/instruction/
account.rs

1use {
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        // TODO field with no name
28        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}