gmsol_sdk/utils/
zero_copy.rs1use std::sync::Arc;
2
3use anchor_lang::{err, Discriminator};
4use gmsol_programs::{
5 anchor_lang,
6 bytemuck::{self, PodCastError},
7};
8
9pub fn check_discriminator<T: Discriminator>(data: &[u8]) -> anchor_lang::prelude::Result<()> {
11 use anchor_lang::error::ErrorCode;
12
13 let disc = T::DISCRIMINATOR;
14 if data.len() < disc.len() {
15 return err!(ErrorCode::AccountDiscriminatorNotFound);
16 }
17 let given_disc = &data[..8];
18 if disc != given_disc {
19 return err!(ErrorCode::AccountDiscriminatorMismatch);
20 }
21 Ok(())
22}
23
24pub fn try_deserialize<T>(data: &[u8]) -> anchor_lang::prelude::Result<T>
28where
29 T: anchor_lang::ZeroCopy,
30{
31 check_discriminator::<T>(data)?;
32 try_deserialize_unchecked(data)
33}
34
35pub fn try_deserialize_unchecked<T>(data: &[u8]) -> anchor_lang::prelude::Result<T>
39where
40 T: anchor_lang::ZeroCopy,
41{
42 use anchor_lang::{error, error::ErrorCode};
43 let end = std::mem::size_of::<T>() + 8;
44 if data.len() < end {
45 return err!(ErrorCode::AccountDidNotDeserialize);
46 }
47 let data_without_discriminator = &data[8..end];
48
49 match bytemuck::try_from_bytes(data_without_discriminator) {
50 Ok(data) => Ok(*data),
51 Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) => {
52 bytemuck::try_pod_read_unaligned(data_without_discriminator)
53 .map_err(|_| error!(ErrorCode::AccountDidNotDeserialize))
54 }
55 Err(_) => Err(error!(ErrorCode::AccountDidNotDeserialize)),
56 }
57}
58
59#[derive(Debug, Clone, Copy)]
61pub struct ZeroCopy<T>(pub T);
62
63impl<T> ZeroCopy<T> {
64 pub fn into_inner(self) -> T {
66 self.0
67 }
68}
69
70impl<T> anchor_lang::AccountDeserialize for ZeroCopy<T>
71where
72 T: anchor_lang::ZeroCopy,
73{
74 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
75 let account = try_deserialize(buf)?;
76 Ok(Self(account))
77 }
78
79 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
80 let account = try_deserialize_unchecked(buf)?;
81 Ok(Self(account))
82 }
83}
84
85impl<T> Discriminator for ZeroCopy<T>
86where
87 T: Discriminator,
88{
89 const DISCRIMINATOR: &'static [u8] = T::DISCRIMINATOR;
90}
91
92impl<T> AsRef<T> for ZeroCopy<T> {
93 fn as_ref(&self) -> &T {
94 &self.0
95 }
96}
97
98pub fn try_deserialize_zero_copy_with_options<T: anchor_lang::ZeroCopy>(
100 mut data: &[u8],
101 no_discriminator: bool,
102) -> crate::Result<ZeroCopy<T>> {
103 use anchor_lang::AccountDeserialize;
104 if no_discriminator {
105 let data = [T::DISCRIMINATOR, data].concat();
106 Ok(ZeroCopy::<T>::try_deserialize(&mut data.as_slice())?)
107 } else {
108 Ok(ZeroCopy::<T>::try_deserialize(&mut data)?)
109 }
110}
111
112pub fn try_deserialize_zero_copy<T: anchor_lang::ZeroCopy>(
114 data: &[u8],
115) -> crate::Result<ZeroCopy<T>> {
116 try_deserialize_zero_copy_with_options(data, false)
117}
118
119pub fn try_deserialize_zero_copy_from_base64_with_options<T: anchor_lang::ZeroCopy>(
121 data: &str,
122 no_discriminator: bool,
123) -> crate::Result<ZeroCopy<T>> {
124 let mut data = crate::utils::base64::decode_base64(data)?;
125 if no_discriminator {
126 data = [T::DISCRIMINATOR, &data].concat();
127 }
128 try_deserialize_zero_copy(&data)
129}
130
131pub fn try_deserialize_zero_copy_from_base64<T: anchor_lang::ZeroCopy>(
133 data: &str,
134) -> crate::Result<ZeroCopy<T>> {
135 try_deserialize_zero_copy_from_base64_with_options(data, false)
136}
137
138pub struct SharedZeroCopy<T>(pub Arc<T>);
140
141impl<T> Clone for SharedZeroCopy<T> {
142 fn clone(&self) -> Self {
143 Self(self.0.clone())
144 }
145}
146
147impl<T> SharedZeroCopy<T> {
148 pub fn into_inner(self) -> Arc<T> {
150 self.0
151 }
152}
153
154impl<T> anchor_lang::AccountDeserialize for SharedZeroCopy<T>
155where
156 T: anchor_lang::ZeroCopy,
157{
158 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
159 let account = try_deserialize(buf)?;
160 Ok(Self(Arc::new(account)))
161 }
162
163 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
164 let account = try_deserialize_unchecked(buf)?;
165 Ok(Self(Arc::new(account)))
166 }
167}
168
169impl<T> Discriminator for SharedZeroCopy<T>
170where
171 T: Discriminator,
172{
173 const DISCRIMINATOR: &'static [u8] = T::DISCRIMINATOR;
174}
175
176impl<T> AsRef<T> for SharedZeroCopy<T> {
177 fn as_ref(&self) -> &T {
178 &self.0
179 }
180}
181
182pub struct Shared<T>(pub Arc<T>);
184
185impl<T> Clone for Shared<T> {
186 fn clone(&self) -> Self {
187 Self(self.0.clone())
188 }
189}
190
191impl<T> Shared<T> {
192 pub fn into_inner(self) -> Arc<T> {
194 self.0
195 }
196}
197
198impl<T> anchor_lang::AccountDeserialize for Shared<T>
199where
200 T: anchor_lang::AccountDeserialize,
201{
202 fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
203 let account = T::try_deserialize(buf)?;
204 Ok(Self(Arc::new(account)))
205 }
206
207 fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
208 let account = T::try_deserialize_unchecked(buf)?;
209 Ok(Self(Arc::new(account)))
210 }
211}
212
213impl<T> Discriminator for Shared<T>
214where
215 T: Discriminator,
216{
217 const DISCRIMINATOR: &'static [u8] = T::DISCRIMINATOR;
218}
219
220impl<T> AsRef<T> for Shared<T> {
221 fn as_ref(&self) -> &T {
222 &self.0
223 }
224}