jito_bytemuck/
lib.rs

1//! Trait that can be used when working with Solana structs that are used as accounts.
2
3pub mod types;
4
5use bytemuck::Pod;
6pub use jito_account_traits_derive::AccountDeserialize;
7use solana_program::{msg, program_error::ProgramError};
8
9pub trait Discriminator {
10    const DISCRIMINATOR: u8;
11}
12
13pub trait AccountDeserialize: Sized + Pod + Discriminator {
14    /// Deserialize the account data into a struct.
15    /// It assumes the first byte is the discriminator and the next seven bytes are reserved.
16    /// The rest of the data is deserialized into the struct.
17    ///
18    /// # Arguments
19    /// * `data` - The account data to deserialize
20    ///
21    /// # Returns
22    /// * `Result<&Self, ProgramError>` - The deserialized struct as a reference or an error
23    fn try_from_slice_unchecked(data: &[u8]) -> Result<&Self, ProgramError> {
24        if data.first() != Some(&Self::DISCRIMINATOR) {
25            msg!(
26                "Discriminator is invalid; expected {}, got {}",
27                Self::DISCRIMINATOR,
28                data.first().unwrap()
29            );
30            return Err(ProgramError::InvalidAccountData);
31        }
32        bytemuck::try_from_bytes(&data[8..]).map_err(|_| ProgramError::InvalidAccountData)
33    }
34
35    /// Deserialize the account data into a mutable struct.
36    /// It assumes the first byte is the discriminator and the next seven bytes are reserved.
37    /// The rest of the data is deserialized into the struct.
38    ///
39    /// # Arguments
40    /// * `data` - The account data to deserialize
41    ///
42    /// # Returns
43    /// * `Result<&mut Self, ProgramError>` - The deserialized struct as a reference or an error
44    fn try_from_slice_unchecked_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError> {
45        if data.first() != Some(&Self::DISCRIMINATOR) {
46            msg!(
47                "Discriminator is invalid; expected {}, got {}",
48                Self::DISCRIMINATOR,
49                data.first().unwrap()
50            );
51            return Err(ProgramError::InvalidAccountData);
52        }
53        bytemuck::try_from_bytes_mut(&mut data[8..]).map_err(|_| ProgramError::InvalidAccountData)
54    }
55}