|
@@ -1,10 +1,7 @@
|
|
|
//! Type facilitating on demand zero copy deserialization.
|
|
|
|
|
|
use crate::error::ErrorCode;
|
|
|
-use crate::{
|
|
|
- Accounts, AccountsClose, AccountsExit, Owner, ToAccountInfo, ToAccountInfos, ToAccountMetas,
|
|
|
- ZeroCopy,
|
|
|
-};
|
|
|
+use crate::*;
|
|
|
use arrayref::array_ref;
|
|
|
use solana_program::account_info::AccountInfo;
|
|
|
use solana_program::entrypoint::ProgramResult;
|
|
@@ -14,7 +11,6 @@ use solana_program::pubkey::Pubkey;
|
|
|
use std::cell::{Ref, RefMut};
|
|
|
use std::collections::BTreeMap;
|
|
|
use std::fmt;
|
|
|
-use std::io::Write;
|
|
|
use std::marker::PhantomData;
|
|
|
use std::mem;
|
|
|
use std::ops::DerefMut;
|
|
@@ -24,8 +20,6 @@ use std::ops::DerefMut;
|
|
|
/// Note that using accounts in this way is distinctly different from using,
|
|
|
/// for example, the [`Account`](./struct.Account.html). Namely,
|
|
|
/// one must call
|
|
|
-/// - `load_init` after initializing an account (this will ignore the missing
|
|
|
-/// account discriminator that gets added only after the user's instruction code)
|
|
|
/// - `load` when the account is not mutable
|
|
|
/// - `load_mut` when the account is mutable
|
|
|
///
|
|
@@ -117,7 +111,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Constructs a new `Loader` from a previously initialized account.
|
|
|
+ /// Constructs a new `AccountLoader` from a previously initialized account.
|
|
|
#[inline(never)]
|
|
|
pub fn try_from(
|
|
|
acc_info: &AccountInfo<'info>,
|
|
@@ -127,7 +121,11 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
}
|
|
|
let data: &[u8] = &acc_info.try_borrow_data()?;
|
|
|
// Discriminator must match.
|
|
|
+ #[cfg(feature = "deprecated-layout")]
|
|
|
let disc_bytes = array_ref![data, 0, 8];
|
|
|
+ #[cfg(not(feature = "deprecated-layout"))]
|
|
|
+ let disc_bytes = array_ref![data, 2, 4];
|
|
|
+
|
|
|
if disc_bytes != &T::discriminator() {
|
|
|
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
|
|
|
}
|
|
@@ -135,7 +133,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
Ok(AccountLoader::new(acc_info.clone()))
|
|
|
}
|
|
|
|
|
|
- /// Constructs a new `Loader` from an uninitialized account.
|
|
|
+ /// Constructs a new `AccountLoader` from an uninitialized account.
|
|
|
#[inline(never)]
|
|
|
pub fn try_from_unchecked(
|
|
|
_program_id: &Pubkey,
|
|
@@ -146,16 +144,18 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
}
|
|
|
Ok(AccountLoader::new(acc_info.clone()))
|
|
|
}
|
|
|
-
|
|
|
/// Returns a Ref to the account data structure for reading.
|
|
|
pub fn load(&self) -> Result<Ref<T>, ProgramError> {
|
|
|
let data = self.acc_info.try_borrow_data()?;
|
|
|
|
|
|
+ #[cfg(feature = "deprecated-layout")]
|
|
|
let disc_bytes = array_ref![data, 0, 8];
|
|
|
+ #[cfg(not(feature = "deprecated-layout"))]
|
|
|
+ let disc_bytes = array_ref![data, 2, 4];
|
|
|
+
|
|
|
if disc_bytes != &T::discriminator() {
|
|
|
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
|
|
|
}
|
|
|
-
|
|
|
Ok(Ref::map(data, |data| {
|
|
|
bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8])
|
|
|
}))
|
|
@@ -171,7 +171,11 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
|
|
|
let data = self.acc_info.try_borrow_mut_data()?;
|
|
|
|
|
|
+ #[cfg(feature = "deprecated-layout")]
|
|
|
let disc_bytes = array_ref![data, 0, 8];
|
|
|
+ #[cfg(not(feature = "deprecated-layout"))]
|
|
|
+ let disc_bytes = array_ref![data, 2, 4];
|
|
|
+
|
|
|
if disc_bytes != &T::discriminator() {
|
|
|
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
|
|
|
}
|
|
@@ -180,30 +184,6 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
|
|
|
bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::<T>() + 8])
|
|
|
}))
|
|
|
}
|
|
|
-
|
|
|
- /// Returns a `RefMut` to the account data structure for reading or writing.
|
|
|
- /// Should only be called once, when the account is being initialized.
|
|
|
- pub fn load_init(&self) -> Result<RefMut<T>, ProgramError> {
|
|
|
- // AccountInfo api allows you to borrow mut even if the account isn't
|
|
|
- // writable, so add this check for a better dev experience.
|
|
|
- if !self.acc_info.is_writable {
|
|
|
- return Err(ErrorCode::AccountNotMutable.into());
|
|
|
- }
|
|
|
-
|
|
|
- let data = self.acc_info.try_borrow_mut_data()?;
|
|
|
-
|
|
|
- // The discriminator should be zero, since we're initializing.
|
|
|
- let mut disc_bytes = [0u8; 8];
|
|
|
- disc_bytes.copy_from_slice(&data[..8]);
|
|
|
- let discriminator = u64::from_le_bytes(disc_bytes);
|
|
|
- if discriminator != 0 {
|
|
|
- return Err(ErrorCode::AccountDiscriminatorAlreadySet.into());
|
|
|
- }
|
|
|
-
|
|
|
- Ok(RefMut::map(data, |data| {
|
|
|
- bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::<T>() + 8])
|
|
|
- }))
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
impl<'info, T: ZeroCopy + Owner> Accounts<'info> for AccountLoader<'info, T> {
|
|
@@ -227,10 +207,7 @@ impl<'info, T: ZeroCopy + Owner> Accounts<'info> for AccountLoader<'info, T> {
|
|
|
impl<'info, T: ZeroCopy + Owner> AccountsExit<'info> for AccountLoader<'info, T> {
|
|
|
// The account *cannot* be loaded when this is called.
|
|
|
fn exit(&self, _program_id: &Pubkey) -> ProgramResult {
|
|
|
- let mut data = self.acc_info.try_borrow_mut_data()?;
|
|
|
- let dst: &mut [u8] = &mut data;
|
|
|
- let mut cursor = std::io::Cursor::new(dst);
|
|
|
- cursor.write_all(&T::discriminator()).unwrap();
|
|
|
+ // No-op.
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
@@ -263,3 +240,10 @@ impl<'info, T: ZeroCopy + Owner> ToAccountInfos<'info> for AccountLoader<'info,
|
|
|
vec![self.acc_info.clone()]
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[cfg(not(feature = "deprecated-layout"))]
|
|
|
+impl<'a, T: ZeroCopy + Owner> Bump for AccountLoader<'a, T> {
|
|
|
+ fn seed(&self) -> u8 {
|
|
|
+ self.acc_info.data.borrow()[1]
|
|
|
+ }
|
|
|
+}
|