1use light_zero_copy::ZeroCopy;
2use spl_pod::solana_msg::msg;
3
4use crate::{
5 state::extensions::{
6 CompressedOnlyExtension, CompressedOnlyExtensionConfig, CompressibleExtension,
7 CompressibleExtensionConfig, ExtensionType, PausableAccountExtension,
8 PausableAccountExtensionConfig, PermanentDelegateAccountExtension,
9 PermanentDelegateAccountExtensionConfig, TokenMetadata, TokenMetadataConfig,
10 TransferFeeAccountExtension, TransferFeeAccountExtensionConfig,
11 TransferHookAccountExtension, TransferHookAccountExtensionConfig,
12 ZPausableAccountExtensionMut, ZPermanentDelegateAccountExtensionMut, ZTokenMetadataMut,
13 ZTransferFeeAccountExtensionMut, ZTransferHookAccountExtensionMut,
14 },
15 AnchorDeserialize, AnchorSerialize,
16};
17
18#[derive(Debug, Clone, Hash, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, ZeroCopy)]
19#[repr(C)]
20pub enum ExtensionStruct {
21 Placeholder0,
22 Placeholder1,
23 Placeholder2,
24 Placeholder3,
25 Placeholder4,
26 Placeholder5,
27 Placeholder6,
28 Placeholder7,
29 Placeholder8,
30 Placeholder9,
31 Placeholder10,
32 Placeholder11,
33 Placeholder12,
34 Placeholder13,
35 Placeholder14,
36 Placeholder15,
37 Placeholder16,
38 Placeholder17,
39 Placeholder18,
40 TokenMetadata(TokenMetadata),
41 Placeholder20,
42 Placeholder21,
43 Placeholder22,
44 Placeholder23,
45 Placeholder24,
46 Placeholder25,
47 Placeholder26,
49 PausableAccount(PausableAccountExtension),
51 PermanentDelegateAccount(PermanentDelegateAccountExtension),
53 TransferFeeAccount(TransferFeeAccountExtension),
55 TransferHookAccount(TransferHookAccountExtension),
57 CompressedOnly(CompressedOnlyExtension),
59 Compressible(CompressibleExtension),
61}
62
63#[derive(Debug)]
64pub enum ZExtensionStructMut<'a> {
65 Placeholder0,
66 Placeholder1,
67 Placeholder2,
68 Placeholder3,
69 Placeholder4,
70 Placeholder5,
71 Placeholder6,
72 Placeholder7,
73 Placeholder8,
74 Placeholder9,
75 Placeholder10,
76 Placeholder11,
77 Placeholder12,
78 Placeholder13,
79 Placeholder14,
80 Placeholder15,
81 Placeholder16,
82 Placeholder17,
83 Placeholder18,
84 TokenMetadata(ZTokenMetadataMut<'a>),
85 Placeholder20,
86 Placeholder21,
87 Placeholder22,
88 Placeholder23,
89 Placeholder24,
90 Placeholder25,
91 Placeholder26,
93 PausableAccount(ZPausableAccountExtensionMut<'a>),
95 PermanentDelegateAccount(ZPermanentDelegateAccountExtensionMut<'a>),
97 TransferFeeAccount(ZTransferFeeAccountExtensionMut<'a>),
99 TransferHookAccount(ZTransferHookAccountExtensionMut<'a>),
101 CompressedOnly(
103 <CompressedOnlyExtension as light_zero_copy::traits::ZeroCopyAtMut<'a>>::ZeroCopyAtMut,
104 ),
105 Compressible(
107 <CompressibleExtension as light_zero_copy::traits::ZeroCopyAtMut<'a>>::ZeroCopyAtMut,
108 ),
109}
110
111impl<'a> light_zero_copy::traits::ZeroCopyAtMut<'a> for ExtensionStruct {
112 type ZeroCopyAtMut = ZExtensionStructMut<'a>;
113
114 fn zero_copy_at_mut(
115 data: &'a mut [u8],
116 ) -> Result<(Self::ZeroCopyAtMut, &'a mut [u8]), light_zero_copy::errors::ZeroCopyError> {
117 if data.is_empty() {
119 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
120 1,
121 data.len(),
122 ));
123 }
124
125 let discriminant = data[0];
126 let remaining_data = &mut data[1..];
127 let extension_type = ExtensionType::try_from(discriminant)
128 .map_err(|_| light_zero_copy::errors::ZeroCopyError::InvalidConversion)?;
129
130 match extension_type {
131 ExtensionType::TokenMetadata => {
132 let (token_metadata, remaining_bytes) =
133 TokenMetadata::zero_copy_at_mut(remaining_data)?;
134 Ok((
135 ZExtensionStructMut::TokenMetadata(token_metadata),
136 remaining_bytes,
137 ))
138 }
139 ExtensionType::PausableAccount => {
140 let (pausable_ext, remaining_bytes) =
141 PausableAccountExtension::zero_copy_at_mut(remaining_data)?;
142 Ok((
143 ZExtensionStructMut::PausableAccount(pausable_ext),
144 remaining_bytes,
145 ))
146 }
147 ExtensionType::PermanentDelegateAccount => {
148 let (permanent_delegate_ext, remaining_bytes) =
149 PermanentDelegateAccountExtension::zero_copy_at_mut(remaining_data)?;
150 Ok((
151 ZExtensionStructMut::PermanentDelegateAccount(permanent_delegate_ext),
152 remaining_bytes,
153 ))
154 }
155 ExtensionType::TransferFeeAccount => {
156 let (transfer_fee_ext, remaining_bytes) =
157 TransferFeeAccountExtension::zero_copy_at_mut(remaining_data)?;
158 Ok((
159 ZExtensionStructMut::TransferFeeAccount(transfer_fee_ext),
160 remaining_bytes,
161 ))
162 }
163 ExtensionType::TransferHookAccount => {
164 let (transfer_hook_ext, remaining_bytes) =
165 TransferHookAccountExtension::zero_copy_at_mut(remaining_data)?;
166 Ok((
167 ZExtensionStructMut::TransferHookAccount(transfer_hook_ext),
168 remaining_bytes,
169 ))
170 }
171 ExtensionType::CompressedOnly => {
172 let (compressed_only_ext, remaining_bytes) =
173 CompressedOnlyExtension::zero_copy_at_mut(remaining_data)?;
174 Ok((
175 ZExtensionStructMut::CompressedOnly(compressed_only_ext),
176 remaining_bytes,
177 ))
178 }
179 ExtensionType::Compressible => {
180 let (compressible_ext, remaining_bytes) =
181 CompressibleExtension::zero_copy_at_mut(remaining_data)?;
182 Ok((
183 ZExtensionStructMut::Compressible(compressible_ext),
184 remaining_bytes,
185 ))
186 }
187 _ => Err(light_zero_copy::errors::ZeroCopyError::InvalidConversion),
188 }
189 }
190}
191
192impl<'a> light_zero_copy::ZeroCopyNew<'a> for ExtensionStruct {
193 type ZeroCopyConfig = ExtensionStructConfig;
194 type Output = ZExtensionStructMut<'a>;
195
196 fn byte_len(
197 config: &Self::ZeroCopyConfig,
198 ) -> Result<usize, light_zero_copy::errors::ZeroCopyError> {
199 Ok(match config {
200 ExtensionStructConfig::TokenMetadata(token_metadata_config) => {
201 1 + TokenMetadata::byte_len(token_metadata_config)?
203 }
204 ExtensionStructConfig::PausableAccount(config) => {
205 1 + PausableAccountExtension::byte_len(config)?
207 }
208 ExtensionStructConfig::PermanentDelegateAccount(config) => {
209 1 + PermanentDelegateAccountExtension::byte_len(config)?
211 }
212 ExtensionStructConfig::TransferFeeAccount(config) => {
213 1 + TransferFeeAccountExtension::byte_len(config)?
215 }
216 ExtensionStructConfig::TransferHookAccount(config) => {
217 1 + TransferHookAccountExtension::byte_len(config)?
219 }
220 ExtensionStructConfig::CompressedOnly(_) => {
221 1 + CompressedOnlyExtension::LEN
223 }
224 ExtensionStructConfig::Compressible(_) => {
225 1 + CompressibleExtension::LEN
227 }
228 _ => {
229 msg!("Invalid extension type returning");
230 return Err(light_zero_copy::errors::ZeroCopyError::InvalidConversion);
231 }
232 })
233 }
234
235 fn new_zero_copy(
236 bytes: &'a mut [u8],
237 config: Self::ZeroCopyConfig,
238 ) -> Result<(Self::Output, &'a mut [u8]), light_zero_copy::errors::ZeroCopyError> {
239 match config {
240 ExtensionStructConfig::TokenMetadata(config) => {
241 if bytes.is_empty() {
242 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
243 1,
244 bytes.len(),
245 ));
246 }
247 bytes[0] = ExtensionType::TokenMetadata as u8;
248
249 let (token_metadata, remaining_bytes) =
250 TokenMetadata::new_zero_copy(&mut bytes[1..], config)?;
251 Ok((
252 ZExtensionStructMut::TokenMetadata(token_metadata),
253 remaining_bytes,
254 ))
255 }
256 ExtensionStructConfig::PausableAccount(config) => {
257 if bytes.is_empty() {
258 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
259 1,
260 bytes.len(),
261 ));
262 }
263 bytes[0] = ExtensionType::PausableAccount as u8;
264
265 let (pausable_ext, remaining_bytes) =
266 PausableAccountExtension::new_zero_copy(&mut bytes[1..], config)?;
267 Ok((
268 ZExtensionStructMut::PausableAccount(pausable_ext),
269 remaining_bytes,
270 ))
271 }
272 ExtensionStructConfig::PermanentDelegateAccount(config) => {
273 if bytes.is_empty() {
274 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
275 1,
276 bytes.len(),
277 ));
278 }
279 bytes[0] = ExtensionType::PermanentDelegateAccount as u8;
280
281 let (permanent_delegate_ext, remaining_bytes) =
282 PermanentDelegateAccountExtension::new_zero_copy(&mut bytes[1..], config)?;
283 Ok((
284 ZExtensionStructMut::PermanentDelegateAccount(permanent_delegate_ext),
285 remaining_bytes,
286 ))
287 }
288 ExtensionStructConfig::TransferFeeAccount(config) => {
289 if bytes.is_empty() {
290 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
291 1,
292 bytes.len(),
293 ));
294 }
295 bytes[0] = ExtensionType::TransferFeeAccount as u8;
296
297 let (transfer_fee_ext, remaining_bytes) =
298 TransferFeeAccountExtension::new_zero_copy(&mut bytes[1..], config)?;
299 Ok((
300 ZExtensionStructMut::TransferFeeAccount(transfer_fee_ext),
301 remaining_bytes,
302 ))
303 }
304 ExtensionStructConfig::TransferHookAccount(config) => {
305 if bytes.is_empty() {
306 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
307 1,
308 bytes.len(),
309 ));
310 }
311 bytes[0] = ExtensionType::TransferHookAccount as u8;
312
313 let (transfer_hook_ext, remaining_bytes) =
314 TransferHookAccountExtension::new_zero_copy(&mut bytes[1..], config)?;
315 Ok((
316 ZExtensionStructMut::TransferHookAccount(transfer_hook_ext),
317 remaining_bytes,
318 ))
319 }
320 ExtensionStructConfig::CompressedOnly(config) => {
321 if bytes.len() < 1 + CompressedOnlyExtension::LEN {
322 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
323 1 + CompressedOnlyExtension::LEN,
324 bytes.len(),
325 ));
326 }
327 bytes[0] = ExtensionType::CompressedOnly as u8;
328
329 let (compressed_only_ext, remaining_bytes) =
330 CompressedOnlyExtension::new_zero_copy(&mut bytes[1..], config)?;
331 Ok((
332 ZExtensionStructMut::CompressedOnly(compressed_only_ext),
333 remaining_bytes,
334 ))
335 }
336 ExtensionStructConfig::Compressible(config) => {
337 if bytes.len() < 1 + CompressibleExtension::LEN {
338 return Err(light_zero_copy::errors::ZeroCopyError::ArraySize(
339 1 + CompressibleExtension::LEN,
340 bytes.len(),
341 ));
342 }
343 bytes[0] = ExtensionType::Compressible as u8;
344
345 let (compressible_ext, remaining_bytes) =
346 CompressibleExtension::new_zero_copy(&mut bytes[1..], config)?;
347 Ok((
348 ZExtensionStructMut::Compressible(compressible_ext),
349 remaining_bytes,
350 ))
351 }
352 _ => Err(light_zero_copy::errors::ZeroCopyError::InvalidConversion),
353 }
354 }
355}
356
357#[derive(Debug, Clone, PartialEq, Default)]
358pub enum ExtensionStructConfig {
359 #[default]
360 Placeholder0,
361 Placeholder1,
362 Placeholder2,
363 Placeholder3,
364 Placeholder4,
365 Placeholder5,
366 Placeholder6,
367 Placeholder7,
368 Placeholder8,
369 Placeholder9,
370 Placeholder10,
371 Placeholder11,
372 Placeholder12,
373 Placeholder13,
374 Placeholder14,
375 Placeholder15,
376 Placeholder16,
377 Placeholder17,
378 Placeholder18, TokenMetadata(TokenMetadataConfig),
380 Placeholder20,
381 Placeholder21,
382 Placeholder22,
383 Placeholder23,
384 Placeholder24,
385 Placeholder25,
386 Placeholder26,
388 PausableAccount(PausableAccountExtensionConfig),
389 PermanentDelegateAccount(PermanentDelegateAccountExtensionConfig),
390 TransferFeeAccount(TransferFeeAccountExtensionConfig),
391 TransferHookAccount(TransferHookAccountExtensionConfig),
392 CompressedOnly(CompressedOnlyExtensionConfig),
393 Compressible(CompressibleExtensionConfig),
394}