spl_discriminator/
discriminator.rs

1//! The traits and types used to create a discriminator for a type
2
3use {
4    bytemuck::{Pod, Zeroable},
5    solana_program_error::ProgramError,
6    solana_sha256_hasher::hashv,
7};
8
9/// A trait for managing 8-byte discriminators in a slab of bytes
10pub trait SplDiscriminate {
11    /// The 8-byte discriminator as a `[u8; 8]`
12    const SPL_DISCRIMINATOR: ArrayDiscriminator;
13    /// The 8-byte discriminator as a slice (`&[u8]`)
14    const SPL_DISCRIMINATOR_SLICE: &'static [u8] = Self::SPL_DISCRIMINATOR.as_slice();
15}
16
17/// Array Discriminator type
18#[cfg_attr(
19    feature = "borsh",
20    derive(borsh::BorshSerialize, borsh::BorshDeserialize)
21)]
22#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
23#[repr(transparent)]
24pub struct ArrayDiscriminator([u8; ArrayDiscriminator::LENGTH]);
25impl ArrayDiscriminator {
26    /// Size for discriminator in account data
27    pub const LENGTH: usize = 8;
28    /// Uninitialized variant of a discriminator
29    pub const UNINITIALIZED: Self = Self::new([0; Self::LENGTH]);
30    /// Creates a discriminator from an array
31    pub const fn new(value: [u8; Self::LENGTH]) -> Self {
32        Self(value)
33    }
34    /// Get the array as a const slice
35    pub const fn as_slice(&self) -> &[u8] {
36        self.0.as_slice()
37    }
38    /// Creates a new `ArrayDiscriminator` from some hash input string literal
39    pub fn new_with_hash_input(hash_input: &str) -> Self {
40        let hash_bytes = hashv(&[hash_input.as_bytes()]).to_bytes();
41        let mut discriminator_bytes = [0u8; 8];
42        discriminator_bytes.copy_from_slice(&hash_bytes[..8]);
43        Self(discriminator_bytes)
44    }
45}
46impl AsRef<[u8]> for ArrayDiscriminator {
47    fn as_ref(&self) -> &[u8] {
48        &self.0[..]
49    }
50}
51impl AsRef<[u8; ArrayDiscriminator::LENGTH]> for ArrayDiscriminator {
52    fn as_ref(&self) -> &[u8; ArrayDiscriminator::LENGTH] {
53        &self.0
54    }
55}
56impl From<u64> for ArrayDiscriminator {
57    fn from(from: u64) -> Self {
58        Self(from.to_le_bytes())
59    }
60}
61impl From<[u8; Self::LENGTH]> for ArrayDiscriminator {
62    fn from(from: [u8; Self::LENGTH]) -> Self {
63        Self(from)
64    }
65}
66impl TryFrom<&[u8]> for ArrayDiscriminator {
67    type Error = ProgramError;
68    fn try_from(a: &[u8]) -> Result<Self, Self::Error> {
69        <[u8; Self::LENGTH]>::try_from(a)
70            .map(Self::from)
71            .map_err(|_| ProgramError::InvalidAccountData)
72    }
73}
74impl From<ArrayDiscriminator> for [u8; 8] {
75    fn from(from: ArrayDiscriminator) -> Self {
76        from.0
77    }
78}
79impl From<ArrayDiscriminator> for u64 {
80    fn from(from: ArrayDiscriminator) -> Self {
81        u64::from_le_bytes(from.0)
82    }
83}