use hopper_runtime::error::ProgramError;
use hopper_runtime::{AccountView, Address};
use crate::account::{FixedLayout, Pod, VerifiedAccount, VerifiedAccountMut};
use crate::check;
use crate::check::modifier::HopperLayout;
use crate::migrate::MigrationKind;
pub struct MigratingAccount<'a, From, To>
where
From: Pod + FixedLayout + HopperLayout,
To: Pod + FixedLayout + HopperLayout,
{
view: &'a AccountView,
program_id: &'a Address,
_from: core::marker::PhantomData<From>,
_to: core::marker::PhantomData<To>,
}
impl<'a, From, To> MigratingAccount<'a, From, To>
where
From: Pod + FixedLayout + HopperLayout,
To: Pod + FixedLayout + HopperLayout,
{
#[inline]
pub fn from_account(
account: &'a AccountView,
program_id: &'a Address,
) -> Result<Self, ProgramError> {
check::check_owner(account, program_id)?;
check::check_writable(account)?;
let data = account.try_borrow()?;
crate::account::check_header(&data, From::DISC, From::VERSION, &From::LAYOUT_ID)?;
check::check_size(&data, From::LEN_WITH_HEADER)?;
Ok(Self {
view: account,
program_id,
_from: core::marker::PhantomData,
_to: core::marker::PhantomData,
})
}
#[inline]
pub fn old(&self) -> Result<VerifiedAccount<'a, From>, ProgramError> {
let data = self.view.try_borrow()?;
VerifiedAccount::from_ref(data)
}
#[inline]
pub fn old_mut(&self) -> Result<VerifiedAccountMut<'a, From>, ProgramError> {
let data = self.view.try_borrow_mut()?;
VerifiedAccountMut::from_ref_mut(data)
}
#[inline]
pub fn into_latest(&self) -> Result<VerifiedAccountMut<'a, To>, ProgramError> {
let data = self.view.try_borrow_mut()?;
crate::account::check_header(&data, To::DISC, To::VERSION, &To::LAYOUT_ID)?;
check::check_size(&data, To::LEN_WITH_HEADER)?;
VerifiedAccountMut::from_ref_mut(data)
}
#[inline]
pub fn migrate_append(&self, payer: &AccountView) -> Result<(), ProgramError> {
crate::migrate::migrate_append(
self.view,
payer,
self.program_id,
&From::LAYOUT_ID,
To::VERSION,
&To::LAYOUT_ID,
To::DISC,
To::LEN_WITH_HEADER,
)
}
#[inline]
pub fn migration_kind(&self) -> MigrationKind {
if To::LEN_WITH_HEADER > From::LEN_WITH_HEADER && To::DISC == From::DISC {
MigrationKind::Append
} else {
MigrationKind::Full
}
}
#[inline(always)]
pub fn address(&self) -> &Address {
self.view.address()
}
#[inline(always)]
pub fn to_account_view(&self) -> &'a AccountView {
self.view
}
}