spl_discriminator/
discriminator.rs

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