1use core::{fmt, ops};
4
5macro_rules! wire_int {
11 (
12 $(#[$meta:meta])*
13 $name:ident, $native:ty, $size:literal, $canonical:literal
14 ) => {
15 $(#[$meta])*
16 #[derive(Clone, Copy, PartialEq, Eq, Default)]
17 #[repr(transparent)]
18 pub struct $name([u8; $size]);
19
20 const _: () = assert!(core::mem::size_of::<$name>() == $size);
22 const _: () = assert!(core::mem::align_of::<$name>() == 1);
23
24 impl $name {
25 pub const ZERO: Self = Self([0u8; $size]);
27
28 pub const MAX: Self = Self(<$native>::MAX.to_le_bytes());
30
31 pub const MIN: Self = Self(<$native>::MIN.to_le_bytes());
33
34 #[inline(always)]
36 pub const fn new(v: $native) -> Self {
37 Self(v.to_le_bytes())
38 }
39
40 #[inline(always)]
42 pub const fn get(self) -> $native {
43 <$native>::from_le_bytes(self.0)
44 }
45
46 #[inline(always)]
48 pub fn set(&mut self, v: $native) {
49 self.0 = v.to_le_bytes();
50 }
51
52 #[inline(always)]
54 pub fn checked_add_assign(
55 &mut self,
56 rhs: $native,
57 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
58 let next = self
59 .get()
60 .checked_add(rhs)
61 .ok_or(::hopper_runtime::ProgramError::ArithmeticOverflow)?;
62 self.set(next);
63 Ok(())
64 }
65
66 #[inline(always)]
68 pub fn add_assign_checked(
69 &mut self,
70 rhs: $native,
71 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
72 self.checked_add_assign(rhs)
73 }
74
75 #[inline(always)]
77 pub fn checked_sub_assign(
78 &mut self,
79 rhs: $native,
80 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
81 let next = self
82 .get()
83 .checked_sub(rhs)
84 .ok_or(::hopper_runtime::ProgramError::ArithmeticOverflow)?;
85 self.set(next);
86 Ok(())
87 }
88
89 #[inline(always)]
91 pub fn sub_assign_checked(
92 &mut self,
93 rhs: $native,
94 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
95 self.checked_sub_assign(rhs)
96 }
97
98 #[inline(always)]
100 pub fn checked_mul_assign(
101 &mut self,
102 rhs: $native,
103 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
104 let next = self
105 .get()
106 .checked_mul(rhs)
107 .ok_or(::hopper_runtime::ProgramError::ArithmeticOverflow)?;
108 self.set(next);
109 Ok(())
110 }
111
112 #[inline(always)]
114 pub fn mul_assign_checked(
115 &mut self,
116 rhs: $native,
117 ) -> ::core::result::Result<(), ::hopper_runtime::ProgramError> {
118 self.checked_mul_assign(rhs)
119 }
120
121 #[inline(always)]
123 pub const fn as_bytes(&self) -> &[u8; $size] {
124 &self.0
125 }
126
127 #[inline(always)]
129 pub fn as_bytes_mut(&mut self) -> &mut [u8; $size] {
130 &mut self.0
131 }
132 }
133
134 impl From<$native> for $name {
135 #[inline(always)]
136 fn from(v: $native) -> Self {
137 Self::new(v)
138 }
139 }
140
141 impl From<$name> for $native {
142 #[inline(always)]
143 fn from(w: $name) -> Self {
144 w.get()
145 }
146 }
147
148 impl ops::Add<$native> for $name {
149 type Output = Self;
150
151 #[inline(always)]
152 fn add(self, rhs: $native) -> Self::Output {
153 Self::new(self.get() + rhs)
154 }
155 }
156
157 impl ops::Add<Self> for $name {
158 type Output = Self;
159
160 #[inline(always)]
161 fn add(self, rhs: Self) -> Self::Output {
162 Self::new(self.get() + rhs.get())
163 }
164 }
165
166 impl ops::AddAssign<$native> for $name {
167 #[inline(always)]
168 fn add_assign(&mut self, rhs: $native) {
169 self.set(self.get() + rhs);
170 }
171 }
172
173 impl ops::AddAssign<Self> for $name {
174 #[inline(always)]
175 fn add_assign(&mut self, rhs: Self) {
176 self.set(self.get() + rhs.get());
177 }
178 }
179
180 impl ops::Sub<$native> for $name {
181 type Output = Self;
182
183 #[inline(always)]
184 fn sub(self, rhs: $native) -> Self::Output {
185 Self::new(self.get() - rhs)
186 }
187 }
188
189 impl ops::Sub<Self> for $name {
190 type Output = Self;
191
192 #[inline(always)]
193 fn sub(self, rhs: Self) -> Self::Output {
194 Self::new(self.get() - rhs.get())
195 }
196 }
197
198 impl ops::SubAssign<$native> for $name {
199 #[inline(always)]
200 fn sub_assign(&mut self, rhs: $native) {
201 self.set(self.get() - rhs);
202 }
203 }
204
205 impl ops::SubAssign<Self> for $name {
206 #[inline(always)]
207 fn sub_assign(&mut self, rhs: Self) {
208 self.set(self.get() - rhs.get());
209 }
210 }
211
212 impl ops::Mul<$native> for $name {
213 type Output = Self;
214
215 #[inline(always)]
216 fn mul(self, rhs: $native) -> Self::Output {
217 Self::new(self.get() * rhs)
218 }
219 }
220
221 impl ops::Mul<Self> for $name {
222 type Output = Self;
223
224 #[inline(always)]
225 fn mul(self, rhs: Self) -> Self::Output {
226 Self::new(self.get() * rhs.get())
227 }
228 }
229
230 impl ops::MulAssign<$native> for $name {
231 #[inline(always)]
232 fn mul_assign(&mut self, rhs: $native) {
233 self.set(self.get() * rhs);
234 }
235 }
236
237 impl ops::MulAssign<Self> for $name {
238 #[inline(always)]
239 fn mul_assign(&mut self, rhs: Self) {
240 self.set(self.get() * rhs.get());
241 }
242 }
243
244 impl PartialOrd for $name {
245 #[inline(always)]
246 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
247 Some(self.cmp(other))
248 }
249 }
250
251 impl Ord for $name {
252 #[inline(always)]
253 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
254 self.get().cmp(&other.get())
255 }
256 }
257
258 impl fmt::Debug for $name {
259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 write!(f, "{}({})", stringify!($name), self.get())
261 }
262 }
263
264 impl fmt::Display for $name {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 write!(f, "{}", self.get())
267 }
268 }
269
270 unsafe impl crate::abi::WireType for $name {
272 const WIRE_SIZE: usize = $size;
273 const CANONICAL_NAME: &'static str = $canonical;
274 }
275
276 #[cfg(feature = "hopper-native-backend")]
282 unsafe impl ::hopper_runtime::__hopper_native::bytemuck::Zeroable for $name {}
283 #[cfg(feature = "hopper-native-backend")]
284 unsafe impl ::hopper_runtime::__hopper_native::bytemuck::Pod for $name {}
285
286 unsafe impl crate::account::Pod for $name {}
288
289 unsafe impl ::hopper_runtime::__sealed::HopperZeroCopySealed for $name {}
294
295 impl crate::account::FixedLayout for $name {
296 const SIZE: usize = $size;
297 }
298 };
299}
300
301wire_int!(
302 WireU16, u16, 2, "u16"
304);
305
306wire_int!(
307 WireU32, u32, 4, "u32"
309);
310
311wire_int!(
312 WireU64, u64, 8, "u64"
314);
315
316wire_int!(
317 WireU128, u128, 16, "u128"
319);
320
321wire_int!(
322 WireI16, i16, 2, "i16"
324);
325
326wire_int!(
327 WireI32, i32, 4, "i32"
329);
330
331wire_int!(
332 WireI64, i64, 8, "i64"
334);
335
336wire_int!(
337 WireI128, i128, 16, "i128"
339);
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn wire_u64_roundtrip() {
347 let w = WireU64::new(0xDEAD_BEEF_CAFE_BABE);
348 assert_eq!(w.get(), 0xDEAD_BEEF_CAFE_BABE);
349 }
350
351 #[test]
352 fn wire_i64_negative() {
353 let w = WireI64::new(-42);
354 assert_eq!(w.get(), -42);
355 }
356
357 #[test]
358 fn wire_u64_checked_assign_helpers() {
359 let mut w = WireU64::new(10);
360 w.checked_add_assign(5).unwrap();
361 assert_eq!(w.get(), 15);
362 w.checked_sub_assign(3).unwrap();
363 assert_eq!(w.get(), 12);
364 w.checked_mul_assign(2).unwrap();
365 assert_eq!(w.get(), 24);
366 }
367
368 #[test]
369 fn wire_u64_assignment_operators_accept_native_rhs() {
370 let mut w = WireU64::new(10);
371 w += 5;
372 assert_eq!(w.get(), 15);
373 w -= 3;
374 assert_eq!(w.get(), 12);
375 w *= 2;
376 assert_eq!(w.get(), 24);
377
378 assert_eq!((w + 1).get(), 25);
379 assert_eq!((w - 4).get(), 20);
380 assert_eq!((w * 3).get(), 72);
381 }
382
383 #[test]
384 fn wire_assignment_operators_accept_wire_rhs() {
385 let mut w = WireI64::new(10);
386 w += WireI64::new(-3);
387 assert_eq!(w.get(), 7);
388 w -= WireI64::new(2);
389 assert_eq!(w.get(), 5);
390 w *= WireI64::new(-2);
391 assert_eq!(w.get(), -10);
392 }
393
394 #[test]
395 fn wire_u64_checked_assign_overflow_is_reported() {
396 let mut w = WireU64::new(u64::MAX);
397 assert_eq!(
398 w.checked_add_assign(1),
399 Err(::hopper_runtime::ProgramError::ArithmeticOverflow)
400 );
401 assert_eq!(w.get(), u64::MAX);
402 }
403
404 #[test]
405 fn wire_ordering() {
406 let a = WireU32::new(10);
407 let b = WireU32::new(20);
408 assert!(a < b);
409 }
410
411 #[test]
412 fn wire_default_is_zero() {
413 let w = WireU64::default();
414 assert_eq!(w.get(), 0);
415 }
416}