solana_zk_sdk/
pod.rs

1use bytemuck_derive::{Pod, Zeroable};
2
3#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)]
4#[repr(transparent)]
5pub struct PodU16([u8; 2]);
6impl From<u16> for PodU16 {
7    fn from(n: u16) -> Self {
8        Self(n.to_le_bytes())
9    }
10}
11impl From<PodU16> for u16 {
12    fn from(pod: PodU16) -> Self {
13        Self::from_le_bytes(pod.0)
14    }
15}
16
17#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pod, Zeroable)]
19#[repr(transparent)]
20pub struct PodU64([u8; 8]);
21impl From<u64> for PodU64 {
22    fn from(n: u64) -> Self {
23        Self(n.to_le_bytes())
24    }
25}
26impl From<PodU64> for u64 {
27    fn from(pod: PodU64) -> Self {
28        Self::from_le_bytes(pod.0)
29    }
30}
31
32macro_rules! impl_from_str {
33    (TYPE = $type:ident, BYTES_LEN = $bytes_len:expr, BASE64_LEN = $base64_len:expr) => {
34        impl std::str::FromStr for $type {
35            type Err = crate::errors::ParseError;
36
37            fn from_str(s: &str) -> Result<Self, Self::Err> {
38                if s.len() > $base64_len {
39                    return Err(Self::Err::WrongSize);
40                }
41                let mut bytes = [0u8; $bytes_len];
42                let decoded_len = BASE64_STANDARD
43                    .decode_slice(s, &mut bytes)
44                    .map_err(|_| Self::Err::Invalid)?;
45                if decoded_len != $bytes_len {
46                    Err(Self::Err::WrongSize)
47                } else {
48                    Ok($type(bytes))
49                }
50            }
51        }
52    };
53}
54pub(crate) use impl_from_str;
55
56macro_rules! impl_from_bytes {
57    (TYPE = $type:ident, BYTES_LEN = $bytes_len:expr) => {
58        impl std::convert::From<[u8; $bytes_len]> for $type {
59            fn from(bytes: [u8; $bytes_len]) -> Self {
60                Self(bytes)
61            }
62        }
63    };
64}
65pub(crate) use impl_from_bytes;
66
67macro_rules! impl_wasm_bindings {
68    (POD_TYPE = $pod_type:ident, DECODED_TYPE = $decoded_type: ident) => {
69        #[cfg(target_arch = "wasm32")]
70        #[allow(non_snake_case)]
71        #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
72        impl $pod_type {
73            #[wasm_bindgen::prelude::wasm_bindgen(constructor)]
74            pub fn constructor(
75                value: wasm_bindgen::JsValue,
76            ) -> Result<$pod_type, wasm_bindgen::JsValue> {
77                if let Some(base64_str) = value.as_string() {
78                    base64_str
79                        .parse::<$pod_type>()
80                        .map_err(|e| e.to_string().into())
81                } else if let Some(uint8_array) = value.dyn_ref::<js_sys::Uint8Array>() {
82                    bytemuck::try_from_bytes(&uint8_array.to_vec())
83                        .map_err(|err| {
84                            wasm_bindgen::JsValue::from(format!("Invalid Uint8Array: {err:?}"))
85                        })
86                        .map(|value| *value)
87                } else if let Some(array) = value.dyn_ref::<js_sys::Array>() {
88                    let mut bytes = vec![];
89                    let iterator =
90                        js_sys::try_iter(&array.values())?.expect("array to be iterable");
91                    for x in iterator {
92                        let x = x?;
93
94                        if let Some(n) = x.as_f64() {
95                            if (0. ..=255.).contains(&n) {
96                                bytes.push(n as u8);
97                                continue;
98                            }
99                        }
100                        return Err(format!("Invalid array argument: {:?}", x).into());
101                    }
102
103                    bytemuck::try_from_bytes(&bytes)
104                        .map_err(|err| {
105                            wasm_bindgen::JsValue::from(format!("Invalid Array: {err:?}"))
106                        })
107                        .map(|value| *value)
108                } else if value.is_undefined() {
109                    Ok($pod_type::default())
110                } else {
111                    Err("Unsupported argument".into())
112                }
113            }
114
115            pub fn toString(&self) -> String {
116                self.to_string()
117            }
118
119            pub fn equals(&self, other: &$pod_type) -> bool {
120                self == other
121            }
122
123            pub fn toBytes(&self) -> Box<[u8]> {
124                self.0.into()
125            }
126
127            pub fn zeroed() -> Self {
128                Self::default()
129            }
130
131            pub fn encode(decoded: &$decoded_type) -> $pod_type {
132                (*decoded).into()
133            }
134
135            pub fn decode(&self) -> Result<$decoded_type, wasm_bindgen::JsValue> {
136                (*self)
137                    .try_into()
138                    .map_err(|err| JsValue::from(format!("Invalid encoding: {err:?}")))
139            }
140        }
141    };
142}
143pub(crate) use impl_wasm_bindings;