use crate::constants::account_type::{TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT};
use crate::constants::{
account_size::SPLU_SECONDARY_STRUCT_LEN,
account_size::TURING_MACHINE_ACCOUNT_PREFIX,
constant::PUBKEY_SIZE
};
use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
use serde::{Deserialize, Serialize};
use solana_program::entrypoint::ProgramResult;
use solana_program::{
program_error::ProgramError,
program_pack::Sealed,
pubkey::Pubkey,
};
use crate::error::PortfolioError;
const TYPE_SIZE: usize = 1;
const STATE_SIZE: usize = 1;
const AMOUNT_SIZE: usize = 8;
const VERSION_SIZE: usize = 1;
const DATE_SIZE:usize = 8;
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SpluStateSecondaryStruct {
pub splu_secondary_address: Pubkey,
pub splu_state: u8,
pub splu_secondary_temporal: Pubkey,
}
impl SpluStateSecondaryStruct {
pub fn update_state_splu(&mut self) -> ProgramResult {
self.splu_state = self
.splu_state
.checked_add(1)
.ok_or(PortfolioError::InvalidState)?;
Ok(())
}
pub fn update_state_splu_with_param(&mut self, state: u8) -> ProgramResult {
self.splu_state = state;
Ok(())
}
pub fn reset_splu_secondary(&mut self) -> ProgramResult {
self.splu_state = 0;
Ok(())
}
pub fn update_splu_sec_tmp(&mut self, splu_sec_tmp: Pubkey) -> ProgramResult {
self.splu_secondary_temporal = splu_sec_tmp;
Ok(())
}
}
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct TuringMachineAccount {
pub type_account: u8,
pub owner: Pubkey,
pub splm_n_asset: Pubkey,
pub state: u8,
pub amount: u64,
pub version: u8,
pub date: i64,
pub splu_state_list: Vec<SpluStateSecondaryStruct>,
}
impl Sealed for TuringMachineAccount {}
pub trait IsInitializedTuringMachine {
fn is_initialized(&self) -> bool;
}
impl IsInitializedTuringMachine for TuringMachineAccount {
fn is_initialized(&self) -> bool {
return (self.type_account == TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT) || (self.type_account == TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
}
}
pub trait PackTuringMachineAccount {
fn unpack_turing_machine_account(src: &[u8]) -> Result<TuringMachineAccount, ProgramError>;
fn pack_turing_machine_account(&self, dst: &mut [u8]);
}
impl PackTuringMachineAccount for TuringMachineAccount {
fn unpack_turing_machine_account(src: &[u8]) -> Result<Self, ProgramError> {
let numbre_splu_state =
(&src.len() - TURING_MACHINE_ACCOUNT_PREFIX) / SPLU_SECONDARY_STRUCT_LEN;
let len_splu_data = &src.len() - TURING_MACHINE_ACCOUNT_PREFIX;
let src_fix = array_ref![&src, 0, TURING_MACHINE_ACCOUNT_PREFIX];
let (type_account, owner, splm_n_asset, state, amount, version, date) = array_refs![
src_fix,
TYPE_SIZE,
PUBKEY_SIZE,
PUBKEY_SIZE,
STATE_SIZE,
AMOUNT_SIZE,
VERSION_SIZE,
DATE_SIZE
];
let mut splu_vec: Vec<SpluStateSecondaryStruct> = Vec::with_capacity(numbre_splu_state);
let list_splu_data = &src[TURING_MACHINE_ACCOUNT_PREFIX
..TURING_MACHINE_ACCOUNT_PREFIX + (len_splu_data) as usize];
let mut offset = 0;
for _ in 0..numbre_splu_state {
let splu_secondary = array_ref![list_splu_data, offset, SPLU_SECONDARY_STRUCT_LEN];
#[allow(clippy::ptr_offset_with_cast)]
let (splu_secondary_address, splu_state,splu_secondary_temporal) = array_refs![splu_secondary, PUBKEY_SIZE, 1,PUBKEY_SIZE];
splu_vec.push(SpluStateSecondaryStruct {
splu_secondary_address: Pubkey::new_from_array(*splu_secondary_address),
splu_state: u8::from_le_bytes(*splu_state),
splu_secondary_temporal: Pubkey::new_from_array(*splu_secondary_temporal),
});
offset += SPLU_SECONDARY_STRUCT_LEN;
}
Ok(TuringMachineAccount {
type_account: u8::from_le_bytes(*type_account),
owner: Pubkey::new_from_array(*owner),
splm_n_asset: Pubkey::new_from_array(*splm_n_asset),
state: u8::from_le_bytes(*state),
amount: u64::from_le_bytes(*amount),
version: u8::from_le_bytes(*version),
date: i64::from_le_bytes(*date),
splu_state_list: splu_vec.to_vec(),
})
}
fn pack_turing_machine_account(&self, dst: &mut [u8]) {
let dst_tmp = array_mut_ref![dst, 0, TURING_MACHINE_ACCOUNT_PREFIX];
let (type_account_dst, owner_dst, splm_n_asset_dst, state_dst, amount_dst, version_dst,date_dst) = mut_array_refs![
dst_tmp,
TYPE_SIZE,
PUBKEY_SIZE,
PUBKEY_SIZE,
STATE_SIZE,
AMOUNT_SIZE,
VERSION_SIZE,
DATE_SIZE
];
let TuringMachineAccount {
type_account,
owner,
splm_n_asset,
state,
amount,
version,
date,
splu_state_list,
} = self;
let splu_vec_tmp = bincode::serialize(&splu_state_list).unwrap();
let len_splu = splu_vec_tmp.len();
let nbre_splu = (len_splu - 8) / SPLU_SECONDARY_STRUCT_LEN;
let len_slu_reel = nbre_splu * SPLU_SECONDARY_STRUCT_LEN;
let mut splu_data_tmp = [0; SPLU_SECONDARY_STRUCT_LEN * 10];
splu_data_tmp[0..len_slu_reel as usize].clone_from_slice(&splu_vec_tmp[8..len_splu]);
*type_account_dst = type_account.to_le_bytes();
owner_dst.copy_from_slice(owner.as_ref());
splm_n_asset_dst.copy_from_slice(splm_n_asset.as_ref());
*state_dst = state.to_le_bytes();
*amount_dst = amount.to_le_bytes();
*version_dst = version.to_le_bytes();
*date_dst = date.to_le_bytes();
dst[TURING_MACHINE_ACCOUNT_PREFIX..TURING_MACHINE_ACCOUNT_PREFIX + len_slu_reel as usize]
.copy_from_slice(&splu_data_tmp[0..len_slu_reel]);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::account_type::TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;
#[test]
fn test_pack_turing_account() {
let type_account = TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;
let owner = Pubkey::new_unique();
let state = 0;
let splm_n_asset = Pubkey::new_unique();
let amount = 2;
let version = 1;
let date = 234;
let splu_struct = SpluStateSecondaryStruct {
splu_secondary_address: Pubkey::new_unique(),
splu_state: 0,
splu_secondary_temporal: Pubkey::new_unique(),
};
let mut splu_state_list = Vec::new();
splu_state_list.push(splu_struct);
let turing = TuringMachineAccount {
type_account,
owner,
splm_n_asset,
state,
amount,
version,
date,
splu_state_list,
};
const LEN: usize = TURING_MACHINE_ACCOUNT_PREFIX + (SPLU_SECONDARY_STRUCT_LEN * 1); let mut packed = [0u8; LEN];
TuringMachineAccount::pack_turing_machine_account(&turing, &mut packed[..]);
let unpacked = TuringMachineAccount::unpack_turing_machine_account(&packed).unwrap();
assert_eq!(turing, unpacked);
assert_eq!(unpacked.type_account, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
}
}