typhoon-context-macro 0.1.0-alpha.2

TODO
Documentation
use {
    super::{ConstraintGenerator, GeneratorResult},
    crate::{
        accounts::Account,
        constraints::{ConstraintInit, ConstraintInitIfNeeded},
        visitor::ContextVisitor,
    },
    proc_macro2::TokenStream,
    quote::quote,
};

struct AccountGenerator<'a> {
    account: &'a Account,
    has_init: bool,
    has_init_if_needed: bool,
}

impl<'a> AccountGenerator<'a> {
    pub fn new(account: &'a Account) -> Self {
        Self {
            account,
            has_init: false,
            has_init_if_needed: false,
        }
    }

    pub fn generate(&self) -> Result<TokenStream, syn::Error> {
        let name = &self.account.name;
        if self.has_init {
            Ok(quote! {
                let #name = <Mut<SystemAccount> as FromAccountInfo>::try_from_info(#name)?;
            })
        } else if self.has_init_if_needed {
            Ok(quote! {
                let #name = <Mut<UncheckedAccount> as FromAccountInfo>::try_from_info(#name)?;
            })
        } else {
            let account_ty = &self.account.ty;
            Ok(quote! {
                let #name = <#account_ty as FromAccountInfo>::try_from_info(#name)?;
            })
        }
    }
}

impl ContextVisitor for AccountGenerator<'_> {
    fn visit_init(&mut self, _constraint: &ConstraintInit) -> Result<(), syn::Error> {
        self.has_init = true;

        Ok(())
    }

    fn visit_init_if_needed(
        &mut self,
        _constraint: &ConstraintInitIfNeeded,
    ) -> Result<(), syn::Error> {
        self.has_init_if_needed = true;

        Ok(())
    }
}

#[derive(Default)]
pub struct AssignGenerator {
    result: GeneratorResult,
}

impl AssignGenerator {
    pub fn new() -> Self {
        AssignGenerator::default()
    }
}

impl ConstraintGenerator for AssignGenerator {
    fn generate(&self) -> Result<GeneratorResult, syn::Error> {
        Ok(self.result.clone())
    }
}

impl ContextVisitor for AssignGenerator {
    fn visit_account(&mut self, account: &Account) -> Result<(), syn::Error> {
        let mut generator = AccountGenerator::new(account);
        generator.visit_account(account)?;
        let token = generator.generate()?;
        self.result.at_init.extend(token);

        Ok(())
    }
}