1#![deny(missing_docs)]
5#![no_std]
6#![cfg_attr(not(test), forbid(unsafe_code))]
7
8extern crate self as spl_discriminator;
9
10pub mod discriminator;
12
13pub use {
15 discriminator::{ArrayDiscriminator, SplDiscriminate},
16 spl_discriminator_derive::SplDiscriminate,
17};
18
19#[cfg(test)]
20mod tests {
21 use {super::*, crate::discriminator::ArrayDiscriminator};
22
23 #[allow(dead_code)]
24 #[derive(SplDiscriminate)]
25 #[discriminator_hash_input("my_first_instruction")]
26 pub struct MyInstruction1<'a> {
27 arg1: &'a str,
28 arg2: u8,
29 }
30
31 #[allow(dead_code)]
32 #[derive(SplDiscriminate)]
33 #[discriminator_hash_input("global:my_second_instruction")]
34 pub enum MyInstruction2 {
35 One,
36 Two,
37 Three,
38 }
39
40 #[allow(dead_code)]
41 #[derive(SplDiscriminate)]
42 #[discriminator_hash_input("global:my_instruction_with_lifetime")]
43 pub struct MyInstruction3<'a> {
44 data: &'a [u8],
45 }
46
47 #[allow(dead_code)]
48 #[derive(SplDiscriminate)]
49 #[discriminator_hash_input("global:my_instruction_with_one_generic")]
50 pub struct MyInstruction4<T> {
51 data: T,
52 }
53
54 #[allow(dead_code)]
55 #[derive(SplDiscriminate)]
56 #[discriminator_hash_input("global:my_instruction_with_one_generic_and_lifetime")]
57 pub struct MyInstruction5<'b, T> {
58 data: &'b [T],
59 }
60
61 #[allow(dead_code)]
62 #[derive(SplDiscriminate)]
63 #[discriminator_hash_input("global:my_instruction_with_multiple_generics_and_lifetime")]
64 pub struct MyInstruction6<'c, U, V> {
65 data1: &'c [U],
66 data2: &'c [V],
67 }
68
69 #[allow(dead_code)]
70 #[derive(SplDiscriminate)]
71 #[discriminator_hash_input(
72 "global:my_instruction_with_multiple_generics_and_lifetime_and_where"
73 )]
74 pub struct MyInstruction7<'c, U, V>
75 where
76 U: Clone + Copy,
77 V: Clone + Copy,
78 {
79 data1: &'c [U],
80 data2: &'c [V],
81 }
82
83 fn assert_discriminator<T: spl_discriminator::discriminator::SplDiscriminate>(
84 hash_input: &str,
85 ) {
86 let discriminator = build_discriminator(hash_input);
87 assert_eq!(
88 T::SPL_DISCRIMINATOR,
89 discriminator,
90 "Discriminator mismatch: case: {}",
91 hash_input
92 );
93 assert_eq!(
94 T::SPL_DISCRIMINATOR_SLICE,
95 discriminator.as_slice(),
96 "Discriminator mismatch: case: {}",
97 hash_input
98 );
99 }
100
101 fn build_discriminator(hash_input: &str) -> ArrayDiscriminator {
102 let preimage = solana_sha256_hasher::hashv(&[hash_input.as_bytes()]);
103 let mut bytes = [0u8; 8];
104 bytes.copy_from_slice(&preimage.to_bytes()[..8]);
105 ArrayDiscriminator::new(bytes)
106 }
107
108 #[test]
109 fn test_discrminators() {
110 let runtime_discrim = ArrayDiscriminator::new_with_hash_input("my_runtime_hash_input");
111 assert_eq!(
112 runtime_discrim,
113 build_discriminator("my_runtime_hash_input"),
114 );
115
116 assert_discriminator::<MyInstruction1<'_>>("my_first_instruction");
117 assert_discriminator::<MyInstruction2>("global:my_second_instruction");
118 assert_discriminator::<MyInstruction3<'_>>("global:my_instruction_with_lifetime");
119 assert_discriminator::<MyInstruction4<u8>>("global:my_instruction_with_one_generic");
120 assert_discriminator::<MyInstruction5<'_, u8>>(
121 "global:my_instruction_with_one_generic_and_lifetime",
122 );
123 assert_discriminator::<MyInstruction6<'_, u8, u8>>(
124 "global:my_instruction_with_multiple_generics_and_lifetime",
125 );
126 assert_discriminator::<MyInstruction7<'_, u8, u8>>(
127 "global:my_instruction_with_multiple_generics_and_lifetime_and_where",
128 );
129 }
130}
131
132#[cfg(all(test, feature = "borsh"))]
133mod borsh_test {
134 use {super::*, borsh::BorshDeserialize};
135
136 #[test]
137 fn borsh_test() {
138 let my_discrim = ArrayDiscriminator::new_with_hash_input("my_discrim");
139 let mut buffer = [0u8; 8];
140 borsh::to_writer(&mut buffer[..], &my_discrim).unwrap();
141 let my_discrim_again = ArrayDiscriminator::try_from_slice(&buffer).unwrap();
142 assert_eq!(my_discrim, my_discrim_again);
143 assert_eq!(buffer, <[u8; 8]>::from(my_discrim));
144 }
145}