//! This code was AUTOGENERATED using the codama library.
//! Please DO NOT EDIT THIS FILE, instead use visitors
//! to add features, then rerun codama to update it.
//!
//! <https://github.com/codama-idl/codama>
//!

#[cfg(feature = "shared-data")]
use std::sync::Arc;

#[cfg(feature = "shared-data")]
use yellowstone_vixen_core::InstructionUpdateOutput;

use crate::deserialize_checked;

use crate::instructions::{
    AdvanceNonceAccount as AdvanceNonceAccountIxAccounts, Allocate as AllocateIxAccounts,
    AllocateInstructionArgs as AllocateIxData, AllocateWithSeed as AllocateWithSeedIxAccounts,
    AllocateWithSeedInstructionArgs as AllocateWithSeedIxData, Assign as AssignIxAccounts,
    AssignInstructionArgs as AssignIxData, AssignWithSeed as AssignWithSeedIxAccounts,
    AssignWithSeedInstructionArgs as AssignWithSeedIxData,
    AuthorizeNonceAccount as AuthorizeNonceAccountIxAccounts,
    AuthorizeNonceAccountInstructionArgs as AuthorizeNonceAccountIxData,
    CreateAccount as CreateAccountIxAccounts, CreateAccountInstructionArgs as CreateAccountIxData,
    CreateAccountWithSeed as CreateAccountWithSeedIxAccounts,
    CreateAccountWithSeedInstructionArgs as CreateAccountWithSeedIxData,
    InitializeNonceAccount as InitializeNonceAccountIxAccounts,
    InitializeNonceAccountInstructionArgs as InitializeNonceAccountIxData,
    TransferSol as TransferSolIxAccounts, TransferSolInstructionArgs as TransferSolIxData,
    TransferSolWithSeed as TransferSolWithSeedIxAccounts,
    TransferSolWithSeedInstructionArgs as TransferSolWithSeedIxData,
    UpgradeNonceAccount as UpgradeNonceAccountIxAccounts,
    WithdrawNonceAccount as WithdrawNonceAccountIxAccounts,
    WithdrawNonceAccountInstructionArgs as WithdrawNonceAccountIxData,
};
use crate::ID;

/// System Instructions
#[derive(Debug)]
#[cfg_attr(feature = "tracing", derive(strum_macros::Display))]
pub enum SystemProgramIx {
    CreateAccount(CreateAccountIxAccounts, CreateAccountIxData),
    Assign(AssignIxAccounts, AssignIxData),
    TransferSol(TransferSolIxAccounts, TransferSolIxData),
    CreateAccountWithSeed(CreateAccountWithSeedIxAccounts, CreateAccountWithSeedIxData),
    AdvanceNonceAccount(AdvanceNonceAccountIxAccounts),
    WithdrawNonceAccount(WithdrawNonceAccountIxAccounts, WithdrawNonceAccountIxData),
    InitializeNonceAccount(
        InitializeNonceAccountIxAccounts,
        InitializeNonceAccountIxData,
    ),
    AuthorizeNonceAccount(AuthorizeNonceAccountIxAccounts, AuthorizeNonceAccountIxData),
    Allocate(AllocateIxAccounts, AllocateIxData),
    AllocateWithSeed(AllocateWithSeedIxAccounts, AllocateWithSeedIxData),
    AssignWithSeed(AssignWithSeedIxAccounts, AssignWithSeedIxData),
    TransferSolWithSeed(TransferSolWithSeedIxAccounts, TransferSolWithSeedIxData),
    UpgradeNonceAccount(UpgradeNonceAccountIxAccounts),
}

#[derive(Debug, Copy, Clone)]
pub struct InstructionParser;

impl yellowstone_vixen_core::Parser for InstructionParser {
    type Input = yellowstone_vixen_core::instruction::InstructionUpdate;

    #[cfg(not(feature = "shared-data"))]
    type Output = SystemProgramIx;

    #[cfg(feature = "shared-data")]
    type Output = InstructionUpdateOutput<SystemProgramIx>;

    fn id(&self) -> std::borrow::Cow<str> {
        "System::InstructionParser".into()
    }

    fn prefilter(&self) -> yellowstone_vixen_core::Prefilter {
        yellowstone_vixen_core::Prefilter::builder()
            .transaction_accounts([ID])
            .build()
            .unwrap()
    }

    async fn parse(
        &self,
        ix_update: &yellowstone_vixen_core::instruction::InstructionUpdate,
    ) -> yellowstone_vixen_core::ParseResult<Self::Output> {
        if ix_update.program.equals_ref(ID) {
            let res = InstructionParser::parse_impl(ix_update);

            #[cfg(feature = "tracing")]
            if let Err(e) = &res {
                let ix_discriminator: [u8; 4] = ix_update.data[0..4].try_into()?;

                tracing::info!(
                    name: "incorrectly_parsed_instruction",
                    name = "ix_update",
                    program = ID.to_string(),
                    ix = "deserialization_error",
                    discriminator = ?ix_discriminator,
                    error = ?e
                );
            }

            res
        } else {
            Err(yellowstone_vixen_core::ParseError::Filtered)
        }
    }
}

impl yellowstone_vixen_core::ProgramParser for InstructionParser {
    #[inline]
    fn program_id(&self) -> yellowstone_vixen_core::Pubkey {
        ID.to_bytes().into()
    }
}

impl InstructionParser {
    pub(crate) fn parse_impl(
        ix: &yellowstone_vixen_core::instruction::InstructionUpdate,
    ) -> yellowstone_vixen_core::ParseResult<<Self as yellowstone_vixen_core::Parser>::Output> {
        let accounts_len = ix.accounts.len();
        let accounts = &mut ix.accounts.iter();

        #[cfg(feature = "shared-data")]
        let shared_data = Arc::clone(&ix.shared);

        let ix_discriminator: [u8; 4] = ix.data[0..4].try_into()?;
        let ix_data = &ix.data[4..];
        let ix = match ix_discriminator {
            [0, 0, 0, 0] => {
                let expected_accounts_len = 2;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = CreateAccountIxAccounts {
                    payer: next_account(accounts)?,
                    new_account: next_account(accounts)?,
                };
                let de_ix_data: CreateAccountIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::CreateAccount(ix_accounts, de_ix_data))
            }
            [1, 0, 0, 0] => {
                let expected_accounts_len = 1;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AssignIxAccounts {
                    account: next_account(accounts)?,
                };
                let de_ix_data: AssignIxData = deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::Assign(ix_accounts, de_ix_data))
            }
            [2, 0, 0, 0] => {
                let expected_accounts_len = 2;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = TransferSolIxAccounts {
                    source: next_account(accounts)?,
                    destination: next_account(accounts)?,
                };
                let de_ix_data: TransferSolIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::TransferSol(ix_accounts, de_ix_data))
            }
            [3, 0, 0, 0] => {
                let expected_accounts_len = 3;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = CreateAccountWithSeedIxAccounts {
                    payer: next_account(accounts)?,
                    new_account: next_account(accounts)?,
                    base_account: next_account(accounts)?,
                };
                let de_ix_data: CreateAccountWithSeedIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::CreateAccountWithSeed(
                    ix_accounts,
                    de_ix_data,
                ))
            }
            [4, 0, 0, 0] => {
                let expected_accounts_len = 3;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AdvanceNonceAccountIxAccounts {
                    nonce_account: next_account(accounts)?,
                    recent_blockhashes_sysvar: next_account(accounts)?,
                    nonce_authority: next_account(accounts)?,
                };
                Ok(SystemProgramIx::AdvanceNonceAccount(ix_accounts))
            }
            [5, 0, 0, 0] => {
                let expected_accounts_len = 5;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = WithdrawNonceAccountIxAccounts {
                    nonce_account: next_account(accounts)?,
                    recipient_account: next_account(accounts)?,
                    recent_blockhashes_sysvar: next_account(accounts)?,
                    rent_sysvar: next_account(accounts)?,
                    nonce_authority: next_account(accounts)?,
                };
                let de_ix_data: WithdrawNonceAccountIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::WithdrawNonceAccount(
                    ix_accounts,
                    de_ix_data,
                ))
            }
            [6, 0, 0, 0] => {
                let expected_accounts_len = 3;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = InitializeNonceAccountIxAccounts {
                    nonce_account: next_account(accounts)?,
                    recent_blockhashes_sysvar: next_account(accounts)?,
                    rent_sysvar: next_account(accounts)?,
                };
                let de_ix_data: InitializeNonceAccountIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::InitializeNonceAccount(
                    ix_accounts,
                    de_ix_data,
                ))
            }
            [7, 0, 0, 0] => {
                let expected_accounts_len = 2;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AuthorizeNonceAccountIxAccounts {
                    nonce_account: next_account(accounts)?,
                    nonce_authority: next_account(accounts)?,
                };
                let de_ix_data: AuthorizeNonceAccountIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::AuthorizeNonceAccount(
                    ix_accounts,
                    de_ix_data,
                ))
            }
            [8, 0, 0, 0] => {
                let expected_accounts_len = 1;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AllocateIxAccounts {
                    new_account: next_account(accounts)?,
                };
                let de_ix_data: AllocateIxData = deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::Allocate(ix_accounts, de_ix_data))
            }
            [9, 0, 0, 0] => {
                let expected_accounts_len = 2;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AllocateWithSeedIxAccounts {
                    new_account: next_account(accounts)?,
                    base_account: next_account(accounts)?,
                };
                let de_ix_data: AllocateWithSeedIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::AllocateWithSeed(ix_accounts, de_ix_data))
            }
            [10, 0, 0, 0] => {
                let expected_accounts_len = 2;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = AssignWithSeedIxAccounts {
                    account: next_account(accounts)?,
                    base_account: next_account(accounts)?,
                };
                let de_ix_data: AssignWithSeedIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::AssignWithSeed(ix_accounts, de_ix_data))
            }
            [11, 0, 0, 0] => {
                let expected_accounts_len = 3;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = TransferSolWithSeedIxAccounts {
                    source: next_account(accounts)?,
                    base_account: next_account(accounts)?,
                    destination: next_account(accounts)?,
                };
                let de_ix_data: TransferSolWithSeedIxData =
                    deserialize_checked(ix_data, &ix_discriminator)?;
                Ok(SystemProgramIx::TransferSolWithSeed(
                    ix_accounts,
                    de_ix_data,
                ))
            }
            [12, 0, 0, 0] => {
                let expected_accounts_len = 1;
                check_min_accounts_req(accounts_len, expected_accounts_len)?;
                let ix_accounts = UpgradeNonceAccountIxAccounts {
                    nonce_account: next_account(accounts)?,
                };
                Ok(SystemProgramIx::UpgradeNonceAccount(ix_accounts))
            }
            _ => Err(yellowstone_vixen_core::ParseError::from(
                "Invalid Instruction discriminator".to_owned(),
            )),
        };

        #[cfg(feature = "tracing")]
        match &ix {
            Ok(ix) => {
                tracing::info!(
                    name: "correctly_parsed_instruction",
                    name = "ix_update",
                    program = ID.to_string(),
                    ix = ix.to_string()
                );
            }
            Err(e) => {
                tracing::info!(
                    name: "incorrectly_parsed_instruction",
                    name = "ix_update",
                    program = ID.to_string(),
                    ix = "error",
                    discriminator = ?ix_discriminator,
                    error = ?e
                );
            }
        }

        #[cfg(not(feature = "shared-data"))]
        return ix;

        #[cfg(feature = "shared-data")]
        ix.map(|ix| InstructionUpdateOutput {
            parsed_ix: ix,
            shared_data,
        })
    }
}

pub fn check_min_accounts_req(
    actual: usize,
    expected: usize,
) -> yellowstone_vixen_core::ParseResult<()> {
    if actual < expected {
        Err(yellowstone_vixen_core::ParseError::from(format!(
            "Too few accounts provided: expected {expected}, got {actual}"
        )))
    } else {
        Ok(())
    }
}

fn next_account<'a, T: Iterator<Item = &'a yellowstone_vixen_core::KeyBytes<32>>>(
    accounts: &mut T,
) -> Result<solana_pubkey::Pubkey, yellowstone_vixen_core::ParseError> {
    accounts
        .next()
        .ok_or(yellowstone_vixen_core::ParseError::from(
            "No more accounts to parse",
        ))
        .map(|acc| acc.0.into())
}

/// Gets the next optional account using the ommited account strategy (account is not passed at all at the instruction).
/// ### Be careful to use this function when more than one account is optional in the Instruction.
///  Only by order there is no way to which ones of the optional accounts are present.
pub fn next_optional_account<'a, T: Iterator<Item = &'a yellowstone_vixen_core::KeyBytes<32>>>(
    accounts: &mut T,
    actual_accounts_len: usize,
    expected_accounts_len: &mut usize,
) -> Result<Option<solana_pubkey::Pubkey>, yellowstone_vixen_core::ParseError> {
    if actual_accounts_len == *expected_accounts_len + 1 {
        *expected_accounts_len += 1;
        Ok(Some(next_account(accounts)?))
    } else {
        Ok(None)
    }
}

/// Gets the next optional account using the traditional Program ID strategy.
///  (If account key is the program ID, means account is not present)
pub fn next_program_id_optional_account<
    'a,
    T: Iterator<Item = &'a yellowstone_vixen_core::KeyBytes<32>>,
>(
    accounts: &mut T,
) -> Result<Option<solana_pubkey::Pubkey>, yellowstone_vixen_core::ParseError> {
    let account_key = next_account(accounts)?;
    if account_key.eq(&ID) {
        Ok(None)
    } else {
        Ok(Some(account_key))
    }
}

// #[cfg(feature = "proto")]
mod proto_parser {
    use super::{InstructionParser, SystemProgramIx};
    use crate::proto_def;
    use yellowstone_vixen_core::proto_helper_traits;
    proto_helper_traits!();
    use yellowstone_vixen_core::proto::ParseProto;

    use super::CreateAccountIxAccounts;
    impl IntoProto<proto_def::CreateAccountIxAccounts> for CreateAccountIxAccounts {
        fn into_proto(self) -> proto_def::CreateAccountIxAccounts {
            proto_def::CreateAccountIxAccounts {
                payer: self.payer.to_string(),
                new_account: self.new_account.to_string(),
            }
        }
    }
    use super::CreateAccountIxData;
    impl IntoProto<proto_def::CreateAccountIxData> for CreateAccountIxData {
        fn into_proto(self) -> proto_def::CreateAccountIxData {
            proto_def::CreateAccountIxData {
                lamports: self.lamports,
                space: self.space,
                program_address: self.program_address.to_string(),
            }
        }
    }
    use super::AssignIxAccounts;
    impl IntoProto<proto_def::AssignIxAccounts> for AssignIxAccounts {
        fn into_proto(self) -> proto_def::AssignIxAccounts {
            proto_def::AssignIxAccounts {
                account: self.account.to_string(),
            }
        }
    }
    use super::AssignIxData;
    impl IntoProto<proto_def::AssignIxData> for AssignIxData {
        fn into_proto(self) -> proto_def::AssignIxData {
            proto_def::AssignIxData {
                program_address: self.program_address.to_string(),
            }
        }
    }
    use super::TransferSolIxAccounts;
    impl IntoProto<proto_def::TransferSolIxAccounts> for TransferSolIxAccounts {
        fn into_proto(self) -> proto_def::TransferSolIxAccounts {
            proto_def::TransferSolIxAccounts {
                source: self.source.to_string(),
                destination: self.destination.to_string(),
            }
        }
    }
    use super::TransferSolIxData;
    impl IntoProto<proto_def::TransferSolIxData> for TransferSolIxData {
        fn into_proto(self) -> proto_def::TransferSolIxData {
            proto_def::TransferSolIxData {
                amount: self.amount,
            }
        }
    }
    use super::CreateAccountWithSeedIxAccounts;
    impl IntoProto<proto_def::CreateAccountWithSeedIxAccounts> for CreateAccountWithSeedIxAccounts {
        fn into_proto(self) -> proto_def::CreateAccountWithSeedIxAccounts {
            proto_def::CreateAccountWithSeedIxAccounts {
                payer: self.payer.to_string(),
                new_account: self.new_account.to_string(),
                base_account: self.base_account.to_string(),
            }
        }
    }
    use super::CreateAccountWithSeedIxData;
    impl IntoProto<proto_def::CreateAccountWithSeedIxData> for CreateAccountWithSeedIxData {
        fn into_proto(self) -> proto_def::CreateAccountWithSeedIxData {
            proto_def::CreateAccountWithSeedIxData {
                base: self.base.to_string(),
                seed: self.seed,
                amount: self.amount,
                space: self.space,
                program_address: self.program_address.to_string(),
            }
        }
    }
    use super::AdvanceNonceAccountIxAccounts;
    impl IntoProto<proto_def::AdvanceNonceAccountIxAccounts> for AdvanceNonceAccountIxAccounts {
        fn into_proto(self) -> proto_def::AdvanceNonceAccountIxAccounts {
            proto_def::AdvanceNonceAccountIxAccounts {
                nonce_account: self.nonce_account.to_string(),
                recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.to_string(),
                nonce_authority: self.nonce_authority.to_string(),
            }
        }
    }
    use super::WithdrawNonceAccountIxAccounts;
    impl IntoProto<proto_def::WithdrawNonceAccountIxAccounts> for WithdrawNonceAccountIxAccounts {
        fn into_proto(self) -> proto_def::WithdrawNonceAccountIxAccounts {
            proto_def::WithdrawNonceAccountIxAccounts {
                nonce_account: self.nonce_account.to_string(),
                recipient_account: self.recipient_account.to_string(),
                recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.to_string(),
                rent_sysvar: self.rent_sysvar.to_string(),
                nonce_authority: self.nonce_authority.to_string(),
            }
        }
    }
    use super::WithdrawNonceAccountIxData;
    impl IntoProto<proto_def::WithdrawNonceAccountIxData> for WithdrawNonceAccountIxData {
        fn into_proto(self) -> proto_def::WithdrawNonceAccountIxData {
            proto_def::WithdrawNonceAccountIxData {
                withdraw_amount: self.withdraw_amount,
            }
        }
    }
    use super::InitializeNonceAccountIxAccounts;
    impl IntoProto<proto_def::InitializeNonceAccountIxAccounts> for InitializeNonceAccountIxAccounts {
        fn into_proto(self) -> proto_def::InitializeNonceAccountIxAccounts {
            proto_def::InitializeNonceAccountIxAccounts {
                nonce_account: self.nonce_account.to_string(),
                recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.to_string(),
                rent_sysvar: self.rent_sysvar.to_string(),
            }
        }
    }
    use super::InitializeNonceAccountIxData;
    impl IntoProto<proto_def::InitializeNonceAccountIxData> for InitializeNonceAccountIxData {
        fn into_proto(self) -> proto_def::InitializeNonceAccountIxData {
            proto_def::InitializeNonceAccountIxData {
                nonce_authority: self.nonce_authority.to_string(),
            }
        }
    }
    use super::AuthorizeNonceAccountIxAccounts;
    impl IntoProto<proto_def::AuthorizeNonceAccountIxAccounts> for AuthorizeNonceAccountIxAccounts {
        fn into_proto(self) -> proto_def::AuthorizeNonceAccountIxAccounts {
            proto_def::AuthorizeNonceAccountIxAccounts {
                nonce_account: self.nonce_account.to_string(),
                nonce_authority: self.nonce_authority.to_string(),
            }
        }
    }
    use super::AuthorizeNonceAccountIxData;
    impl IntoProto<proto_def::AuthorizeNonceAccountIxData> for AuthorizeNonceAccountIxData {
        fn into_proto(self) -> proto_def::AuthorizeNonceAccountIxData {
            proto_def::AuthorizeNonceAccountIxData {
                new_nonce_authority: self.new_nonce_authority.to_string(),
            }
        }
    }
    use super::AllocateIxAccounts;
    impl IntoProto<proto_def::AllocateIxAccounts> for AllocateIxAccounts {
        fn into_proto(self) -> proto_def::AllocateIxAccounts {
            proto_def::AllocateIxAccounts {
                new_account: self.new_account.to_string(),
            }
        }
    }
    use super::AllocateIxData;
    impl IntoProto<proto_def::AllocateIxData> for AllocateIxData {
        fn into_proto(self) -> proto_def::AllocateIxData {
            proto_def::AllocateIxData { space: self.space }
        }
    }
    use super::AllocateWithSeedIxAccounts;
    impl IntoProto<proto_def::AllocateWithSeedIxAccounts> for AllocateWithSeedIxAccounts {
        fn into_proto(self) -> proto_def::AllocateWithSeedIxAccounts {
            proto_def::AllocateWithSeedIxAccounts {
                new_account: self.new_account.to_string(),
                base_account: self.base_account.to_string(),
            }
        }
    }
    use super::AllocateWithSeedIxData;
    impl IntoProto<proto_def::AllocateWithSeedIxData> for AllocateWithSeedIxData {
        fn into_proto(self) -> proto_def::AllocateWithSeedIxData {
            proto_def::AllocateWithSeedIxData {
                base: self.base.to_string(),
                seed: self.seed,
                space: self.space,
                program_address: self.program_address.to_string(),
            }
        }
    }
    use super::AssignWithSeedIxAccounts;
    impl IntoProto<proto_def::AssignWithSeedIxAccounts> for AssignWithSeedIxAccounts {
        fn into_proto(self) -> proto_def::AssignWithSeedIxAccounts {
            proto_def::AssignWithSeedIxAccounts {
                account: self.account.to_string(),
                base_account: self.base_account.to_string(),
            }
        }
    }
    use super::AssignWithSeedIxData;
    impl IntoProto<proto_def::AssignWithSeedIxData> for AssignWithSeedIxData {
        fn into_proto(self) -> proto_def::AssignWithSeedIxData {
            proto_def::AssignWithSeedIxData {
                base: self.base.to_string(),
                seed: self.seed,
                program_address: self.program_address.to_string(),
            }
        }
    }
    use super::TransferSolWithSeedIxAccounts;
    impl IntoProto<proto_def::TransferSolWithSeedIxAccounts> for TransferSolWithSeedIxAccounts {
        fn into_proto(self) -> proto_def::TransferSolWithSeedIxAccounts {
            proto_def::TransferSolWithSeedIxAccounts {
                source: self.source.to_string(),
                base_account: self.base_account.to_string(),
                destination: self.destination.to_string(),
            }
        }
    }
    use super::TransferSolWithSeedIxData;
    impl IntoProto<proto_def::TransferSolWithSeedIxData> for TransferSolWithSeedIxData {
        fn into_proto(self) -> proto_def::TransferSolWithSeedIxData {
            proto_def::TransferSolWithSeedIxData {
                amount: self.amount,
                from_seed: self.from_seed,
                from_owner: self.from_owner.to_string(),
            }
        }
    }
    use super::UpgradeNonceAccountIxAccounts;
    impl IntoProto<proto_def::UpgradeNonceAccountIxAccounts> for UpgradeNonceAccountIxAccounts {
        fn into_proto(self) -> proto_def::UpgradeNonceAccountIxAccounts {
            proto_def::UpgradeNonceAccountIxAccounts {
                nonce_account: self.nonce_account.to_string(),
            }
        }
    }

    impl IntoProto<proto_def::ProgramIxs> for SystemProgramIx {
        fn into_proto(self) -> proto_def::ProgramIxs {
            match self {
                SystemProgramIx::CreateAccount(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::CreateAccount(
                        proto_def::CreateAccountIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::Assign(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::Assign(
                        proto_def::AssignIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::TransferSol(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::TransferSol(
                        proto_def::TransferSolIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::CreateAccountWithSeed(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::CreateAccountWithSeed(
                        proto_def::CreateAccountWithSeedIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::AdvanceNonceAccount(acc) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::AdvanceNonceAccount(
                        proto_def::AdvanceNonceAccountIx {
                            accounts: Some(acc.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::WithdrawNonceAccount(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::WithdrawNonceAccount(
                        proto_def::WithdrawNonceAccountIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::InitializeNonceAccount(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::InitializeNonceAccount(
                        proto_def::InitializeNonceAccountIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::AuthorizeNonceAccount(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::AuthorizeNonceAccount(
                        proto_def::AuthorizeNonceAccountIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::Allocate(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::Allocate(
                        proto_def::AllocateIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::AllocateWithSeed(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::AllocateWithSeed(
                        proto_def::AllocateWithSeedIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::AssignWithSeed(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::AssignWithSeed(
                        proto_def::AssignWithSeedIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::TransferSolWithSeed(acc, data) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::TransferSolWithSeed(
                        proto_def::TransferSolWithSeedIx {
                            accounts: Some(acc.into_proto()),
                            data: Some(data.into_proto()),
                        },
                    )),
                },
                SystemProgramIx::UpgradeNonceAccount(acc) => proto_def::ProgramIxs {
                    ix_oneof: Some(proto_def::program_ixs::IxOneof::UpgradeNonceAccount(
                        proto_def::UpgradeNonceAccountIx {
                            accounts: Some(acc.into_proto()),
                        },
                    )),
                },
            }
        }
    }

    impl ParseProto for InstructionParser {
        type Message = proto_def::ProgramIxs;

        fn output_into_message(value: Self::Output) -> Self::Message {
            #[cfg(not(feature = "shared-data"))]
            return value.into_proto();

            #[cfg(feature = "shared-data")]
            value.parsed_ix.into_proto()
        }
    }
}
