1use {
3 bytemuck::{Pod, Zeroable},
4 solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey},
5 safe_zk_token_sdk::zk_token_elgamal::pod,
6 std::convert::TryFrom,
7};
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
12#[repr(transparent)]
13pub struct OptionalNonZeroPubkey(Pubkey);
14impl TryFrom<Option<Pubkey>> for OptionalNonZeroPubkey {
15 type Error = ProgramError;
16 fn try_from(p: Option<Pubkey>) -> Result<Self, Self::Error> {
17 match p {
18 None => Ok(Self(Pubkey::default())),
19 Some(pubkey) => {
20 if pubkey == Pubkey::default() {
21 Err(ProgramError::InvalidArgument)
22 } else {
23 Ok(Self(pubkey))
24 }
25 }
26 }
27 }
28}
29impl TryFrom<COption<Pubkey>> for OptionalNonZeroPubkey {
30 type Error = ProgramError;
31 fn try_from(p: COption<Pubkey>) -> Result<Self, Self::Error> {
32 match p {
33 COption::None => Ok(Self(Pubkey::default())),
34 COption::Some(pubkey) => {
35 if pubkey == Pubkey::default() {
36 Err(ProgramError::InvalidArgument)
37 } else {
38 Ok(Self(pubkey))
39 }
40 }
41 }
42 }
43}
44impl std::fmt::Display for OptionalNonZeroPubkey {
45 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
46 write!(f, "{:?}", &self)
47 }
48}
49impl From<OptionalNonZeroPubkey> for Option<Pubkey> {
50 fn from(p: OptionalNonZeroPubkey) -> Self {
51 if p.0 == Pubkey::default() {
52 None
53 } else {
54 Some(p.0)
55 }
56 }
57}
58impl From<OptionalNonZeroPubkey> for COption<Pubkey> {
59 fn from(p: OptionalNonZeroPubkey) -> Self {
60 if p.0 == Pubkey::default() {
61 COption::None
62 } else {
63 COption::Some(p.0)
64 }
65 }
66}
67
68pub type EncryptionPubkey = pod::ElGamalPubkey;
70#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
72#[repr(transparent)]
73pub struct OptionalNonZeroEncryptionPubkey(EncryptionPubkey);
74impl OptionalNonZeroEncryptionPubkey {
75 pub fn equals(&self, other: &EncryptionPubkey) -> bool {
78 &self.0 == other
79 }
80}
81impl TryFrom<Option<EncryptionPubkey>> for OptionalNonZeroEncryptionPubkey {
82 type Error = ProgramError;
83 fn try_from(p: Option<EncryptionPubkey>) -> Result<Self, Self::Error> {
84 match p {
85 None => Ok(Self(EncryptionPubkey::default())),
86 Some(encryption_pubkey) => {
87 if encryption_pubkey == EncryptionPubkey::default() {
88 Err(ProgramError::InvalidArgument)
89 } else {
90 Ok(Self(encryption_pubkey))
91 }
92 }
93 }
94 }
95}
96impl std::fmt::Display for OptionalNonZeroEncryptionPubkey {
97 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98 write!(f, "{:?}", &self)
99 }
100}
101impl From<OptionalNonZeroEncryptionPubkey> for Option<EncryptionPubkey> {
102 fn from(p: OptionalNonZeroEncryptionPubkey) -> Self {
103 if p.0 == EncryptionPubkey::default() {
104 None
105 } else {
106 Some(p.0)
107 }
108 }
109}
110
111#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
113#[repr(transparent)]
114pub struct PodBool(u8);
115impl From<bool> for PodBool {
116 fn from(b: bool) -> Self {
117 Self(if b { 1 } else { 0 })
118 }
119}
120impl From<&PodBool> for bool {
121 fn from(b: &PodBool) -> Self {
122 b.0 != 0
123 }
124}
125
126impl From<PodBool> for bool {
127 fn from(b: PodBool) -> Self {
128 b.0 != 0
129 }
130}
131
132macro_rules! impl_int_conversion {
137 ($P:ty, $I:ty) => {
138 impl From<$I> for $P {
139 fn from(n: $I) -> Self {
140 Self(n.to_le_bytes())
141 }
142 }
143 impl From<$P> for $I {
144 fn from(pod: $P) -> Self {
145 Self::from_le_bytes(pod.0)
146 }
147 }
148 };
149}
150
151#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
153#[repr(transparent)]
154pub struct PodU16([u8; 2]);
155impl_int_conversion!(PodU16, u16);
156
157#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
159#[repr(transparent)]
160pub struct PodI16([u8; 2]);
161impl_int_conversion!(PodI16, i16);
162
163#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
165#[repr(transparent)]
166pub struct PodU64([u8; 8]);
167impl_int_conversion!(PodU64, u64);
168
169#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
171#[repr(transparent)]
172pub struct PodI64([u8; 8]);
173impl_int_conversion!(PodI64, i64);
174
175pub fn pod_get_packed_len<T: Pod>() -> usize {
177 std::mem::size_of::<T>()
178}
179
180pub fn pod_bytes_of<T: Pod>(t: &T) -> &[u8] {
182 bytemuck::bytes_of(t)
183}
184
185pub fn pod_from_bytes<T: Pod>(bytes: &[u8]) -> Result<&T, ProgramError> {
187 bytemuck::try_from_bytes(bytes).map_err(|_| ProgramError::InvalidArgument)
188}
189
190pub fn pod_maybe_from_bytes<T: Pod>(bytes: &[u8]) -> Result<Option<&T>, ProgramError> {
195 if bytes.is_empty() {
196 Ok(None)
197 } else {
198 bytemuck::try_from_bytes(bytes)
199 .map(Some)
200 .map_err(|_| ProgramError::InvalidArgument)
201 }
202}
203
204pub fn pod_from_bytes_mut<T: Pod>(bytes: &mut [u8]) -> Result<&mut T, ProgramError> {
206 bytemuck::try_from_bytes_mut(bytes).map_err(|_| ProgramError::InvalidArgument)
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_pod_bool() {
215 assert!(pod_from_bytes::<PodBool>(&[]).is_err());
216 assert!(pod_from_bytes::<PodBool>(&[0, 0]).is_err());
217
218 for i in 0..=u8::MAX {
219 assert_eq!(i != 0, bool::from(pod_from_bytes::<PodBool>(&[i]).unwrap()));
220 }
221 }
222
223 #[test]
224 fn test_pod_u64() {
225 assert!(pod_from_bytes::<PodU64>(&[]).is_err());
226 assert_eq!(
227 1u64,
228 u64::from(*pod_from_bytes::<PodU64>(&[1, 0, 0, 0, 0, 0, 0, 0]).unwrap())
229 );
230 }
231
232 #[test]
233 fn test_pod_option() {
234 assert_eq!(
235 Some(Pubkey::new_from_array([1; 32])),
236 Option::<Pubkey>::from(*pod_from_bytes::<OptionalNonZeroPubkey>(&[1; 32]).unwrap())
237 );
238 assert_eq!(
239 None,
240 Option::<Pubkey>::from(*pod_from_bytes::<OptionalNonZeroPubkey>(&[0; 32]).unwrap())
241 );
242 assert!(pod_from_bytes::<OptionalNonZeroPubkey>(&[]).is_err());
243 assert!(pod_from_bytes::<OptionalNonZeroPubkey>(&[0; 1]).is_err());
244 assert!(pod_from_bytes::<OptionalNonZeroPubkey>(&[1; 1]).is_err());
245 }
246}