star_frame 0.30.0

A high performance Solana framework for building fast, scalable, and secure smart contracts.
Documentation
//! `AccountSet` implementations for fixed-size arrays. Enables working with multiple accounts of the same type using `[T; N]` syntax with automatic iteration and validation.

use std::{mem::MaybeUninit, ops::Mul};

use crate::{
    account_set::{
        AccountSetCleanup, AccountSetDecode, AccountSetValidate, ClientAccountSet, CpiAccountSet,
    },
    prelude::*,
};
use array_init::try_array_init;
use typenum::{Const, ToUInt};

unsafe impl<A, const N: usize> CpiAccountSet for [A; N]
where
    A: CpiAccountSet,
    Const<N>: ToUInt,
    A::AccountLen: Mul<typenum::U<N>, Output: typenum::Unsigned>,
{
    type ContainsOption = typenum::False;
    type CpiAccounts = [A::CpiAccounts; N];
    type AccountLen = typenum::Prod<A::AccountLen, typenum::U<N>>;

    #[inline]
    fn to_cpi_accounts(&self) -> Self::CpiAccounts {
        self.each_ref().map(A::to_cpi_accounts)
    }

    #[inline]
    fn write_account_infos<'a>(
        program: Option<&'a AccountInfo>,
        accounts: &'a Self::CpiAccounts,
        index: &mut usize,
        infos: &mut [MaybeUninit<&'a AccountInfo>],
    ) -> Result<()> {
        for acc in accounts {
            A::write_account_infos(program, acc, index, infos)?;
        }
        Ok(())
    }

    #[inline]
    fn write_account_metas<'a>(
        program_id: &'a Pubkey,
        accounts: &'a Self::CpiAccounts,
        index: &mut usize,
        metas: &mut [MaybeUninit<PinocchioAccountMeta<'a>>],
    ) {
        for acc in accounts {
            A::write_account_metas(program_id, acc, index, metas);
        }
    }
}

impl<A, const N: usize> ClientAccountSet for [A; N]
where
    A: ClientAccountSet,
{
    type ClientAccounts = [A::ClientAccounts; N];
    const MIN_LEN: usize = N * A::MIN_LEN;
    #[inline]
    fn extend_account_metas(
        program_id: &Pubkey,
        accounts: &Self::ClientAccounts,
        metas: &mut Vec<AccountMeta>,
    ) {
        for a in accounts {
            A::extend_account_metas(program_id, a, metas);
        }
    }
}

impl<'a, A, const N: usize, DArg> AccountSetDecode<'a, [DArg; N]> for [A; N]
where
    A: AccountSetDecode<'a, DArg>,
{
    fn decode_accounts(
        accounts: &mut &'a [AccountInfo],
        decode_input: [DArg; N],
        ctx: &mut Context,
    ) -> Result<Self> {
        let mut decode_input = decode_input.into_iter();
        try_array_init(|_| A::decode_accounts(accounts, decode_input.next().unwrap(), ctx))
    }
}
impl<'a, A, const N: usize, DArg> AccountSetDecode<'a, (DArg,)> for [A; N]
where
    A: AccountSetDecode<'a, DArg>,
    DArg: Clone,
{
    fn decode_accounts(
        accounts: &mut &'a [AccountInfo],
        decode_input: (DArg,),
        ctx: &mut Context,
    ) -> Result<Self> {
        try_array_init(|_| A::decode_accounts(accounts, decode_input.0.clone(), ctx))
    }
}
impl<'a, A, const N: usize> AccountSetDecode<'a, ()> for [A; N]
where
    A: AccountSetDecode<'a, ()>,
{
    fn decode_accounts(
        accounts: &mut &'a [AccountInfo],
        decode_input: (),
        ctx: &mut Context,
    ) -> Result<Self> {
        Self::decode_accounts(accounts, (decode_input,), ctx)
    }
}

impl<A, const N: usize, VArg> AccountSetValidate<[VArg; N]> for [A; N]
where
    A: AccountSetValidate<VArg>,
{
    fn validate_accounts(&mut self, validate_input: [VArg; N], ctx: &mut Context) -> Result<()> {
        for (a, v) in self.iter_mut().zip(validate_input) {
            a.validate_accounts(v, ctx)?;
        }
        Ok(())
    }
}
impl<A, const N: usize, VArg> AccountSetValidate<(VArg,)> for [A; N]
where
    A: AccountSetValidate<VArg>,
    VArg: Clone,
{
    fn validate_accounts(&mut self, validate_input: (VArg,), ctx: &mut Context) -> Result<()> {
        for a in self {
            a.validate_accounts(validate_input.0.clone(), ctx)?;
        }
        Ok(())
    }
}
impl<A, const N: usize> AccountSetValidate<()> for [A; N]
where
    A: AccountSetValidate<()>,
{
    fn validate_accounts(&mut self, validate_input: (), ctx: &mut Context) -> Result<()> {
        for a in self {
            a.validate_accounts(validate_input, ctx)?;
        }
        Ok(())
    }
}

impl<A, const N: usize, VArg> AccountSetCleanup<[VArg; N]> for [A; N]
where
    A: AccountSetCleanup<VArg>,
{
    fn cleanup_accounts(&mut self, cleanup_input: [VArg; N], ctx: &mut Context) -> Result<()> {
        for (a, v) in self.iter_mut().zip(cleanup_input) {
            a.cleanup_accounts(v, ctx)?;
        }
        Ok(())
    }
}
impl<A, const N: usize, VArg> AccountSetCleanup<(VArg,)> for [A; N]
where
    A: AccountSetCleanup<VArg>,
    VArg: Clone,
{
    fn cleanup_accounts(&mut self, cleanup_input: (VArg,), ctx: &mut Context) -> Result<()> {
        for a in self {
            a.cleanup_accounts(cleanup_input.0.clone(), ctx)?;
        }
        Ok(())
    }
}
impl<A, const N: usize> AccountSetCleanup<()> for [A; N]
where
    A: AccountSetCleanup<()>,
{
    fn cleanup_accounts(&mut self, cleanup_input: (), ctx: &mut Context) -> Result<()> {
        for a in self {
            a.cleanup_accounts(cleanup_input, ctx)?;
        }
        Ok(())
    }
}

#[cfg(all(feature = "idl", not(target_os = "solana")))]
pub mod idl_impl {
    use crate::idl::AccountSetToIdl;
    use star_frame_idl::{account_set::IdlAccountSetDef, IdlDefinition};

    impl<T, const N: usize> AccountSetToIdl<()> for [T; N]
    where
        T: AccountSetToIdl<()>,
    {
        fn account_set_to_idl(
            idl_definition: &mut IdlDefinition,
            arg: (),
        ) -> crate::IdlResult<IdlAccountSetDef> {
            let account_set = Box::new(T::account_set_to_idl(idl_definition, arg)?);
            Ok(IdlAccountSetDef::Many {
                account_set,
                min: N,
                max: Some(N),
            })
        }
    }
}