use crate::account::{FixedLayout, Pod, VerifiedAccount, VerifiedAccountMut};
use crate::check;
use hopper_runtime::error::ProgramError;
use hopper_runtime::{AccountView, Address};
pub struct Account<'a, T: Pod + FixedLayout> {
view: &'a AccountView,
verified: VerifiedAccount<'a, T>,
}
impl<'a, T: Pod + FixedLayout> Account<'a, T> {
#[inline(always)]
pub fn view(&self) -> &'a AccountView {
self.view
}
#[inline(always)]
pub fn get(&self) -> &T {
self.verified.get()
}
#[inline(always)]
pub fn data(&self) -> &[u8] {
self.verified.data()
}
#[inline(always)]
pub fn map<U, F>(&self, f: F) -> U
where
F: FnOnce(&T) -> U,
{
self.verified.map(f)
}
}
pub struct AccountMut<'a, T: Pod + FixedLayout> {
view: &'a AccountView,
verified: VerifiedAccountMut<'a, T>,
}
impl<'a, T: Pod + FixedLayout> AccountMut<'a, T> {
#[inline(always)]
pub fn view(&self) -> &'a AccountView {
self.view
}
#[inline(always)]
pub fn get(&self) -> &T {
self.verified.get()
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
self.verified.get_mut()
}
#[inline(always)]
pub fn map_mut<U, F>(&mut self, f: F) -> U
where
F: FnOnce(&mut T) -> U,
{
self.verified.map_mut(f)
}
}
pub struct Signer<I> {
inner: I,
}
impl<I> Signer<I> {
#[inline(always)]
pub fn inner(&self) -> &I {
&self.inner
}
#[inline(always)]
pub fn into_inner(self) -> I {
self.inner
}
}
pub struct Mut<I> {
inner: I,
}
impl<I> Mut<I> {
#[inline(always)]
pub fn inner(&self) -> &I {
&self.inner
}
#[inline(always)]
pub fn into_inner(self) -> I {
self.inner
}
}
pub trait FromAccount<'a>: Sized {
fn from_account(account: &'a AccountView, program_id: &Address) -> Result<Self, ProgramError>;
}
impl<'a, T: Pod + FixedLayout + HopperLayout> FromAccount<'a> for Account<'a, T> {
#[inline]
fn from_account(account: &'a AccountView, program_id: &Address) -> Result<Self, ProgramError> {
check::check_owner(account, program_id)?;
let data = account.try_borrow()?;
crate::account::check_header(&data, T::DISC, T::VERSION, &T::LAYOUT_ID)?;
check::check_size(&data, T::LEN_WITH_HEADER)?;
let verified = VerifiedAccount::from_ref(data)?;
Ok(Self {
view: account,
verified,
})
}
}
impl<'a, T: Pod + FixedLayout + HopperLayout> FromAccount<'a> for AccountMut<'a, T> {
#[inline]
fn from_account(account: &'a AccountView, program_id: &Address) -> Result<Self, ProgramError> {
check::check_owner(account, program_id)?;
check::check_writable(account)?;
let data = account.try_borrow_mut()?;
crate::account::check_header(&data, T::DISC, T::VERSION, &T::LAYOUT_ID)?;
check::check_size(&data, T::LEN_WITH_HEADER)?;
let verified = VerifiedAccountMut::from_ref_mut(data)?;
Ok(Self {
view: account,
verified,
})
}
}
impl<'a, I: FromAccount<'a> + HasView<'a>> FromAccount<'a> for Signer<I> {
#[inline]
fn from_account(account: &'a AccountView, program_id: &Address) -> Result<Self, ProgramError> {
check::check_signer(account)?;
let inner = I::from_account(account, program_id)?;
Ok(Self { inner })
}
}
impl<'a, I: FromAccount<'a> + HasView<'a>> FromAccount<'a> for Mut<I> {
#[inline]
fn from_account(account: &'a AccountView, program_id: &Address) -> Result<Self, ProgramError> {
check::check_writable(account)?;
let inner = I::from_account(account, program_id)?;
Ok(Self { inner })
}
}
pub trait HasView<'a> {
fn view(&self) -> &'a AccountView;
}
impl<'a, T: Pod + FixedLayout> HasView<'a> for Account<'a, T> {
#[inline(always)]
fn view(&self) -> &'a AccountView {
self.view
}
}
impl<'a, T: Pod + FixedLayout> HasView<'a> for AccountMut<'a, T> {
#[inline(always)]
fn view(&self) -> &'a AccountView {
self.view
}
}
impl<'a, I: HasView<'a>> HasView<'a> for Signer<I> {
#[inline(always)]
fn view(&self) -> &'a AccountView {
self.inner.view()
}
}
impl<'a, I: HasView<'a>> HasView<'a> for Mut<I> {
#[inline(always)]
fn view(&self) -> &'a AccountView {
self.inner.view()
}
}
pub trait HopperLayout: Pod + FixedLayout {
const DISC: u8;
const VERSION: u8;
const LAYOUT_ID: [u8; 8];
const LEN_WITH_HEADER: usize;
}