use super::borrowed::{AccountHeader, DataHeader, STATIC_SIZE};
use super::{ALIGNMENT, StateFlags};
use crate::cow::AccountCore;
use crate::cow::borrowed::IMAGE_OFFSET;
use crate::{Account, AccountMode, AccountSharedData, StorageUnit};
use solana_clock::Slot;
use solana_pubkey::Pubkey;
use std::{ptr::NonNull, sync::Arc};
#[derive(Clone, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct OwnedAccount {
pub(crate) core: AccountCore,
pub(crate) data: Arc<Vec<u8>>,
}
impl OwnedAccount {
pub fn units(&self) -> u32 {
self.allocation() * 2 + IMAGE_OFFSET as u32
}
fn allocation(&self) -> u32 {
(STATIC_SIZE + self.data.len()).div_ceil(ALIGNMENT) as u32
}
pub unsafe fn serialize(&self, buf: &mut [StorageUnit], pubkey: &Pubkey) {
let ptr = NonNull::new_unchecked(buf.as_mut_ptr());
debug_assert_eq!(self.units() as usize, buf.len());
fn write<U, T: Sized>(ptr: NonNull<U>, v: T) -> NonNull<T> {
unsafe {
ptr.cast().write(v);
ptr.cast().add(1)
}
}
let allocation = self.allocation();
let ptr = write(ptr, AccountHeader::new(allocation));
let ptr = write(ptr, *pubkey);
let ptr = write(ptr, self.core);
let len = self.data.len();
let ptr = write(ptr, DataHeader::new(len as u32, allocation)).cast();
self.data.as_ptr().copy_to_nonoverlapping(ptr.as_ptr(), len);
}
pub fn is(&self, mode: AccountMode) -> bool {
self.core.mode == mode
}
pub fn owner(&self) -> Pubkey {
self.core.owner
}
pub fn lamports(&self) -> u64 {
self.core.lamports
}
pub fn mode(&self) -> AccountMode {
self.core.mode
}
pub fn slot(&self) -> u64 {
self.core.slot
}
pub fn flags(&self) -> StateFlags {
self.core.flags
}
pub fn data(&self) -> &[u8] {
&self.data
}
}
#[derive(Default, Clone)]
pub struct AccountBuilder(OwnedAccount);
impl AccountBuilder {
pub fn lamports(mut self, lamports: u64) -> Self {
self.0.core.lamports = lamports;
self
}
pub fn data(mut self, data: impl Into<Arc<Vec<u8>>>) -> Self {
self.0.data = data.into();
self
}
pub fn owner(mut self, owner: Pubkey) -> Self {
self.0.core.owner = owner;
self
}
pub fn mode(mut self, mode: AccountMode) -> Self {
self.0.core.mode = mode;
self
}
pub fn executable(mut self, executable: bool) -> Self {
self.0.core.flags.set(StateFlags::EXECUTABLE, executable);
self
}
pub fn slot(mut self, slot: Slot) -> Self {
self.0.core.slot = slot;
self
}
pub fn read(&self) -> &OwnedAccount {
&self.0
}
pub fn build<A: From<OwnedAccount>>(self) -> A {
self.0.into()
}
}
impl From<Account> for OwnedAccount {
fn from(value: Account) -> Self {
AccountBuilder::default()
.lamports(value.lamports)
.data(value.data)
.owner(value.owner)
.executable(value.executable)
.build()
}
}
impl From<AccountBuilder> for OwnedAccount {
fn from(value: AccountBuilder) -> Self {
value.0
}
}
impl From<Account> for AccountBuilder {
fn from(value: Account) -> Self {
Self(value.into())
}
}
impl From<AccountSharedData> for AccountBuilder {
fn from(value: AccountSharedData) -> Self {
Self(value.owned())
}
}