spherenet_program_whitelist_interface/state/
mod.rs1pub mod account_state;
2pub mod entry;
3pub mod whitelist;
4use {
5 bytemuck::{Pod, Zeroable},
6 core::mem,
7 pinocchio::program_error::ProgramError,
8};
9
10pub trait SizeOf {
12 const SIZE_OF: usize;
14}
15
16impl<T: Pod> SizeOf for T {
18 const SIZE_OF: usize = mem::size_of::<T>();
19}
20
21pub type COption<T> = ([u8; 4], T);
23
24#[repr(C, packed)]
26#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
27pub struct PodCOption<T>
28where
29 T: Pod + Default,
30{
31 pub(crate) option: [u8; 4],
32 pub(crate) value: T,
33}
34
35impl<T> PodCOption<T>
36where
37 T: Pod + Default,
38{
39 pub const NONE: [u8; 4] = [0; 4];
41 pub const SOME: [u8; 4] = [1, 0, 0, 0];
44
45 pub fn none() -> Self {
50 Self {
51 option: Self::NONE,
52 value: T::default(),
53 }
54 }
55
56 pub const fn some(value: T) -> Self {
58 Self {
59 option: Self::SOME,
60 value,
61 }
62 }
63
64 pub fn unwrap_or(self, default: T) -> T {
67 if self.option == Self::NONE {
68 default
69 } else {
70 self.value
71 }
72 }
73
74 pub fn is_some(&self) -> bool {
76 self.option == Self::SOME
77 }
78
79 pub fn is_none(&self) -> bool {
81 self.option == Self::NONE
82 }
83
84 pub fn ok_or<E>(self, error: E) -> Result<T, E> {
86 match self {
87 Self {
88 option: Self::SOME,
89 value,
90 } => Ok(value),
91 _ => Err(error),
92 }
93 }
94}
95
96impl<T: Pod + Default> From<COption<T>> for PodCOption<T> {
97 fn from(opt: COption<T>) -> Self {
98 if opt.0[0] == 0 {
99 Self {
100 option: Self::NONE,
101 value: T::default(),
102 }
103 } else {
104 Self {
105 option: Self::SOME,
106 value: opt.1,
107 }
108 }
109 }
110}
111
112pub trait Initializable {
114 fn is_initialized(&self) -> bool;
116}
117
118#[inline(always)]
120pub fn load<'data, T: Pod + Initializable>(input: &'data [u8]) -> Result<&'data T, ProgramError> {
121 if input.len() != T::SIZE_OF {
122 return Err(ProgramError::InvalidAccountData);
123 }
124
125 let account = bytemuck::from_bytes::<T>(input);
126
127 if !account.is_initialized() {
128 return Err(ProgramError::UninitializedAccount);
129 }
130
131 Ok(account)
132}
133
134#[inline(always)]
136pub fn load_mut<'data, T: Pod + Initializable>(
137 input: &'data mut [u8],
138) -> Result<&'data mut T, ProgramError> {
139 if input.len() != T::SIZE_OF {
140 return Err(ProgramError::InvalidAccountData);
141 }
142
143 let account = bytemuck::from_bytes_mut::<T>(input);
144
145 if !account.is_initialized() {
146 return Err(ProgramError::UninitializedAccount);
147 }
148
149 Ok(account)
150}
151
152#[inline(always)]
154pub fn load_unchecked<'data, T: Pod>(input: &'data [u8]) -> Result<&'data T, ProgramError> {
155 if input.len() != T::SIZE_OF {
156 return Err(ProgramError::InvalidAccountData);
157 }
158
159 Ok(bytemuck::from_bytes::<T>(input))
160}
161
162#[inline(always)]
164pub fn load_mut_unchecked<'data, T: Pod>(
165 input: &'data mut [u8],
166) -> Result<&'data mut T, ProgramError> {
167 if input.len() != T::SIZE_OF {
168 return Err(ProgramError::InvalidAccountData);
169 }
170
171 Ok(bytemuck::from_bytes_mut::<T>(input))
172}