atlas_program_pack/
lib.rs

1//! The [`Pack`] serialization trait
2//! This is a specific serialization API that is used by many older programs in
3//! the [Atlas Program Library][atlas] to manage account state. It is not generally
4//! recommended for new code since it does not define a language-independent
5//! serialization format.
6//!
7//! [atlas]: https://github.com/atlas-labs/atlas-program-library
8#![cfg_attr(docsrs, feature(doc_cfg))]
9
10use atlas_program_error::ProgramError;
11
12/// Check if a program account state is initialized
13pub trait IsInitialized {
14    /// Is initialized
15    fn is_initialized(&self) -> bool;
16}
17
18/// Implementors must have a known size
19pub trait Sealed: Sized {}
20
21/// Safely and efficiently (de)serialize account state
22pub trait Pack: Sealed {
23    /// The length, in bytes, of the packed representation
24    const LEN: usize;
25    #[doc(hidden)]
26    fn pack_into_slice(&self, dst: &mut [u8]);
27    #[doc(hidden)]
28    fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError>;
29
30    /// Get the packed length
31    fn get_packed_len() -> usize {
32        Self::LEN
33    }
34
35    /// Unpack from slice and check if initialized
36    fn unpack(input: &[u8]) -> Result<Self, ProgramError>
37    where
38        Self: IsInitialized,
39    {
40        let value = Self::unpack_unchecked(input)?;
41        if value.is_initialized() {
42            Ok(value)
43        } else {
44            Err(ProgramError::UninitializedAccount)
45        }
46    }
47
48    /// Unpack from slice without checking if initialized
49    fn unpack_unchecked(input: &[u8]) -> Result<Self, ProgramError> {
50        if input.len() != Self::LEN {
51            return Err(ProgramError::InvalidAccountData);
52        }
53        Self::unpack_from_slice(input)
54    }
55
56    /// Pack into slice
57    fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> {
58        if dst.len() != Self::LEN {
59            return Err(ProgramError::InvalidAccountData);
60        }
61        src.pack_into_slice(dst);
62        Ok(())
63    }
64}