1use crate::ZError;
2use core::cmp::Ordering;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::marker::PhantomData;
6#[cfg(feature = "serde")]
7use serde::{Serialize, Serializer};
8
9#[cfg(feature = "alloy")]
10use alloy_primitives::{Address as AlloyAddress, U256 as AlloyU256};
11
12use crate::ZDecode;
15
16#[cfg_attr(feature = "serde", derive(Serialize))]
19#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + ZDecode<'a>"))]
20pub struct ZArray<'a, T> {
21 pub data: &'a [u8],
22 pub start_offset: usize,
23 pub length: usize,
24 pub _marker: PhantomData<T>,
25}
26
27impl<'a, T> Clone for ZArray<'a, T> {
28 fn clone(&self) -> Self {
29 *self
30 }
31}
32
33impl<'a, T> Copy for ZArray<'a, T> {}
34
35impl<'a, T> ZArray<'a, T> {
36 pub fn new(data: &'a [u8], start_offset: usize, length: usize) -> Self {
37 Self {
38 data,
39 start_offset,
40 length,
41 _marker: PhantomData,
42 }
43 }
44
45 pub fn len(&self) -> usize {
46 self.length
47 }
48
49 pub fn is_empty(&self) -> bool {
50 self.length == 0
51 }
52
53 pub fn get(&self, index: usize) -> Result<T, ZError>
54 where
55 T: ZDecode<'a>,
56 {
57 if index >= self.length {
58 return Err(ZError::OutOfBounds(index, self.length));
59 }
60 let offset = self.start_offset + index * 32;
61 T::decode(self.data, offset)
62 }
63}
64
65impl<'a, T: fmt::Debug> fmt::Debug for ZArray<'a, T> {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "ZArray(len={})", self.length)
68 }
69}
70
71pub struct ZArrayIterator<'a, T> {
73 array: ZArray<'a, T>,
74 index: usize,
75}
76
77impl<'a, T: ZDecode<'a>> Iterator for ZArrayIterator<'a, T> {
78 type Item = Result<T, ZError>;
79
80 fn next(&mut self) -> Option<Self::Item> {
81 if self.index >= self.array.len() {
82 None
83 } else {
84 let res = self.array.get(self.index);
85 self.index += 1;
86 Some(res)
87 }
88 }
89}
90
91impl<'a, T: ZDecode<'a>> IntoIterator for ZArray<'a, T> {
92 type Item = Result<T, ZError>;
93 type IntoIter = ZArrayIterator<'a, T>;
94
95 fn into_iter(self) -> Self::IntoIter {
96 ZArrayIterator {
97 array: self,
98 index: 0,
99 }
100 }
101}
102
103impl<'a, T> ZArray<'a, T> {
104 pub fn iter(&self) -> ZArrayIterator<'a, T> {
106 ZArrayIterator {
107 array: *self,
108 index: 0,
109 }
110 }
111}
112
113#[derive(Clone, Copy, PartialEq, Eq)]
115pub struct ZAddress<'a>(pub &'a [u8; 20]);
116
117impl<'a> fmt::Debug for ZAddress<'a> {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "ZAddress(0x")?;
120 for byte in self.0 {
121 write!(f, "{:02x}", byte)?;
122 }
123 write!(f, ")")
124 }
125}
126
127impl<'a> fmt::Display for ZAddress<'a> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 write!(f, "0x")?;
130 for byte in self.0 {
131 write!(f, "{:02x}", byte)?;
132 }
133 Ok(())
134 }
135}
136
137impl<'a> ZAddress<'a> {
138 #[inline]
140 pub fn to_bytes(&self) -> [u8; 20] {
141 *self.0
142 }
143
144 #[inline]
146 pub fn as_bytes(&self) -> &[u8; 20] {
147 self.0
148 }
149
150 #[cfg(feature = "alloy")]
152 #[inline]
153 pub fn to_alloy(&self) -> AlloyAddress {
154 AlloyAddress::from(*self.0)
155 }
156}
157
158#[cfg(feature = "alloy")]
159impl<'a> From<ZAddress<'a>> for AlloyAddress {
160 #[inline]
161 fn from(value: ZAddress<'a>) -> Self {
162 value.to_alloy()
163 }
164}
165
166impl<'a> PartialOrd for ZAddress<'a> {
167 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
168 Some(self.cmp(other))
169 }
170}
171
172impl<'a> Ord for ZAddress<'a> {
173 fn cmp(&self, other: &Self) -> Ordering {
174 self.0.cmp(other.0)
175 }
176}
177
178impl<'a> Hash for ZAddress<'a> {
179 fn hash<H: Hasher>(&self, state: &mut H) {
180 self.0.hash(state);
181 }
182}
183
184#[cfg(feature = "serde")]
185impl<'a> Serialize for ZAddress<'a> {
186 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187 where
188 S: Serializer,
189 {
190 let mut hex_str = alloc::string::String::with_capacity(42);
192 hex_str.push_str("0x");
193 for byte in self.0 {
194 use core::fmt::Write;
195 write!(hex_str, "{:02x}", byte).unwrap();
196 }
197 serializer.serialize_str(&hex_str)
198 }
199}
200
201#[derive(Clone, Copy, PartialEq, Eq)]
203pub struct ZU256<'a>(pub &'a [u8; 32]);
204
205impl<'a> fmt::Debug for ZU256<'a> {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 write!(f, "ZU256(0x")?;
208 for byte in self.0 {
209 write!(f, "{:02x}", byte)?;
210 }
211 write!(f, ")")
212 }
213}
214
215impl<'a> fmt::Display for ZU256<'a> {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 write!(f, "0x")?;
218 for byte in self.0 {
219 write!(f, "{:02x}", byte)?;
220 }
221 Ok(())
222 }
223}
224
225impl<'a> ZU256<'a> {
226 #[inline]
229 pub fn to_u128(&self) -> Option<u128> {
230 for i in 0..16 {
232 if self.0[i] != 0 {
233 return None;
234 }
235 }
236 let mut bytes = [0u8; 16];
237 bytes.copy_from_slice(&self.0[16..32]);
238 Some(u128::from_be_bytes(bytes))
239 }
240
241 #[inline]
244 pub fn to_u64(&self) -> Option<u64> {
245 for i in 0..24 {
247 if self.0[i] != 0 {
248 return None;
249 }
250 }
251 let mut bytes = [0u8; 8];
252 bytes.copy_from_slice(&self.0[24..32]);
253 Some(u64::from_be_bytes(bytes))
254 }
255
256 #[inline]
258 pub fn as_bytes(&self) -> &[u8; 32] {
259 self.0
260 }
261
262 #[inline]
264 pub fn to_bytes(&self) -> [u8; 32] {
265 *self.0
266 }
267
268 #[inline]
270 pub fn is_zero(&self) -> bool {
271 self.0.iter().all(|&b| b == 0)
272 }
273
274 #[inline]
277 pub fn to_u32(&self) -> Option<u32> {
278 for i in 0..28 {
280 if self.0[i] != 0 {
281 return None;
282 }
283 }
284 let mut bytes = [0u8; 4];
285 bytes.copy_from_slice(&self.0[28..32]);
286 Some(u32::from_be_bytes(bytes))
287 }
288
289 #[inline]
291 pub fn to_u16(&self) -> Option<u16> {
292 self.to_u32().and_then(|v| v.try_into().ok())
293 }
294
295 #[inline]
297 pub fn to_u8(&self) -> Option<u8> {
298 self.to_u32().and_then(|v| v.try_into().ok())
299 }
300
301 #[inline]
303 pub fn is_max(&self) -> bool {
304 self.0.iter().all(|&b| b == 0xff)
305 }
306
307 #[cfg(feature = "alloy")]
309 #[inline]
310 pub fn to_alloy(&self) -> AlloyU256 {
311 AlloyU256::from_be_bytes(*self.0)
312 }
313}
314
315#[cfg(feature = "alloy")]
316impl<'a> From<ZU256<'a>> for AlloyU256 {
317 #[inline]
318 fn from(value: ZU256<'a>) -> Self {
319 value.to_alloy()
320 }
321}
322
323impl<'a> PartialOrd for ZU256<'a> {
324 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
325 Some(self.cmp(other))
326 }
327}
328
329impl<'a> Ord for ZU256<'a> {
330 fn cmp(&self, other: &Self) -> Ordering {
331 self.0.cmp(other.0)
332 }
333}
334
335impl<'a> Hash for ZU256<'a> {
336 fn hash<H: Hasher>(&self, state: &mut H) {
337 self.0.hash(state);
338 }
339}
340
341#[cfg(feature = "serde")]
342impl<'a> Serialize for ZU256<'a> {
343 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
344 where
345 S: Serializer,
346 {
347 let mut hex_str = alloc::string::String::with_capacity(66);
348 hex_str.push_str("0x");
349 for byte in self.0 {
350 use core::fmt::Write;
351 write!(hex_str, "{:02x}", byte).unwrap();
352 }
353 serializer.serialize_str(&hex_str)
354 }
355}
356
357#[derive(Clone, Copy, PartialEq, Eq)]
360pub struct ZInt256<'a>(pub &'a [u8; 32]);
361
362impl<'a> fmt::Debug for ZInt256<'a> {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 write!(f, "ZInt256(0x")?;
365 for byte in self.0 {
366 write!(f, "{:02x}", byte)?;
367 }
368 write!(f, ")")
369 }
370}
371
372impl<'a> fmt::Display for ZInt256<'a> {
373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374 write!(f, "0x")?;
376 for byte in self.0 {
377 write!(f, "{:02x}", byte)?;
378 }
379 Ok(())
380 }
381}
382
383impl<'a> ZInt256<'a> {
384 #[inline]
387 pub fn to_i128(&self) -> Option<i128> {
388 let is_negative = self.0[0] & 0x80 != 0;
390 let expected_padding = if is_negative { 0xff } else { 0x00 };
391
392 for i in 0..16 {
394 if self.0[i] != expected_padding {
395 return None;
396 }
397 }
398 let mut bytes = [0u8; 16];
399 bytes.copy_from_slice(&self.0[16..32]);
400 Some(i128::from_be_bytes(bytes))
401 }
402
403 #[inline]
406 pub fn to_i64(&self) -> Option<i64> {
407 let is_negative = self.0[0] & 0x80 != 0;
408 let expected_padding = if is_negative { 0xff } else { 0x00 };
409
410 for i in 0..24 {
412 if self.0[i] != expected_padding {
413 return None;
414 }
415 }
416 let mut bytes = [0u8; 8];
417 bytes.copy_from_slice(&self.0[24..32]);
418 Some(i64::from_be_bytes(bytes))
419 }
420
421 #[inline]
423 pub fn as_bytes(&self) -> &[u8; 32] {
424 self.0
425 }
426
427 #[inline]
429 pub fn is_negative(&self) -> bool {
430 self.0[0] & 0x80 != 0
431 }
432
433 #[inline]
435 pub fn to_i32(&self) -> Option<i32> {
436 let is_negative = self.is_negative();
437 let expected_padding = if is_negative { 0xff } else { 0x00 };
438 for i in 0..28 {
439 if self.0[i] != expected_padding {
440 return None;
441 }
442 }
443 let mut bytes = [0u8; 4];
444 bytes.copy_from_slice(&self.0[28..32]);
445 Some(i32::from_be_bytes(bytes))
446 }
447
448 #[inline]
450 pub fn to_i16(&self) -> Option<i16> {
451 self.to_i32().and_then(|v| v.try_into().ok())
452 }
453
454 #[inline]
456 pub fn to_i8(&self) -> Option<i8> {
457 self.to_i32().and_then(|v| v.try_into().ok())
458 }
459
460 #[inline]
462 pub fn is_positive(&self) -> bool {
463 !self.is_negative() && !self.0.iter().all(|&b| b == 0)
464 }
465
466 #[inline]
470 pub fn abs_bytes(&self) -> [u8; 32] {
471 if !self.is_negative() {
472 *self.0
473 } else {
474 let mut res = [0u8; 32];
475 let mut carry = 1u16;
476 for i in (0..32).rev() {
477 let val = (!self.0[i]) as u16 + carry;
478 res[i] = val as u8;
479 carry = val >> 8;
480 }
481 res
482 }
483 }
484
485 #[inline]
487 pub fn signum(&self) -> i8 {
488 if self.0.iter().all(|&b| b == 0) {
489 0
490 } else if self.is_negative() {
491 -1
492 } else {
493 1
494 }
495 }
496}
497
498impl<'a> PartialOrd for ZInt256<'a> {
503 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
504 Some(self.cmp(other))
505 }
506}
507
508impl<'a> Ord for ZInt256<'a> {
509 fn cmp(&self, other: &Self) -> Ordering {
510 let self_neg = self.is_negative();
511 let other_neg = other.is_negative();
512
513 match (self_neg, other_neg) {
514 (true, true) => {
515 self.0.cmp(other.0)
519 }
520 (false, false) => {
521 self.0.cmp(other.0)
523 }
524 (true, false) => {
525 Ordering::Less
527 }
528 (false, true) => {
529 Ordering::Greater
531 }
532 }
533 }
534}
535
536impl<'a> Hash for ZInt256<'a> {
537 fn hash<H: Hasher>(&self, state: &mut H) {
538 self.0.hash(state);
539 }
540}
541
542#[cfg(feature = "serde")]
543impl<'a> Serialize for ZInt256<'a> {
544 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
545 where
546 S: Serializer,
547 {
548 let mut hex_str = alloc::string::String::with_capacity(66);
550 hex_str.push_str("0x");
551 for byte in self.0 {
552 use core::fmt::Write;
553 write!(hex_str, "{:02x}", byte).unwrap();
554 }
555 serializer.serialize_str(&hex_str)
556 }
557}
558
559#[derive(Clone, Copy, PartialEq, Eq)]
561pub struct ZBytes<'a>(pub &'a [u8]);
562
563impl<'a> fmt::Debug for ZBytes<'a> {
564 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565 write!(f, "ZBytes(len={}, data=0x", self.0.len())?;
566 for (i, byte) in self.0.iter().enumerate() {
567 if i >= 32 {
568 write!(f, "...")?;
570 break;
571 }
572 write!(f, "{:02x}", byte)?;
573 }
574 write!(f, ")")
575 }
576}
577
578impl<'a> fmt::Display for ZBytes<'a> {
579 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580 write!(f, "0x")?;
581 for byte in self.0 {
582 write!(f, "{:02x}", byte)?;
583 }
584 Ok(())
585 }
586}
587
588impl<'a> ZBytes<'a> {
589 #[inline]
591 pub fn len(&self) -> usize {
592 self.0.len()
593 }
594
595 #[inline]
597 pub fn is_empty(&self) -> bool {
598 self.0.is_empty()
599 }
600
601 #[inline]
603 pub fn as_slice(&self) -> &[u8] {
604 self.0
605 }
606}
607
608impl<'a> PartialOrd for ZBytes<'a> {
609 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
610 Some(self.cmp(other))
611 }
612}
613
614impl<'a> Ord for ZBytes<'a> {
615 fn cmp(&self, other: &Self) -> Ordering {
616 self.0.cmp(other.0)
617 }
618}
619
620impl<'a> Hash for ZBytes<'a> {
621 fn hash<H: Hasher>(&self, state: &mut H) {
622 self.0.hash(state);
623 }
624}
625
626#[cfg(feature = "serde")]
627impl<'a> Serialize for ZBytes<'a> {
628 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
629 where
630 S: Serializer,
631 {
632 let mut hex_str = alloc::string::String::with_capacity(2 + self.0.len() * 2);
633 hex_str.push_str("0x");
634 for byte in self.0 {
635 use core::fmt::Write;
636 write!(hex_str, "{:02x}", byte).unwrap();
637 }
638 serializer.serialize_str(&hex_str)
639 }
640}
641
642#[derive(Clone, Copy, PartialEq, Eq)]
645#[cfg_attr(feature = "serde", derive(Serialize))]
646pub struct ZBool(pub bool);
647
648impl fmt::Debug for ZBool {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 write!(f, "ZBool({})", self.0)
651 }
652}
653
654impl fmt::Display for ZBool {
655 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656 write!(f, "{}", self.0)
657 }
658}
659
660impl ZBool {
661 #[inline]
663 pub fn as_bool(&self) -> bool {
664 self.0
665 }
666}
667
668#[derive(Clone, Copy, PartialEq, Eq)]
670#[cfg_attr(feature = "serde", derive(Serialize))]
671pub struct ZString<'a>(pub &'a str);
672
673impl<'a> PartialOrd for ZString<'a> {
674 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
675 Some(self.cmp(other))
676 }
677}
678
679impl<'a> Ord for ZString<'a> {
680 fn cmp(&self, other: &Self) -> Ordering {
681 self.0.cmp(other.0)
682 }
683}
684
685impl<'a> Hash for ZString<'a> {
686 fn hash<H: Hasher>(&self, state: &mut H) {
687 self.0.hash(state);
688 }
689}
690
691impl<'a> fmt::Debug for ZString<'a> {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 write!(f, "ZString({:?})", self.0)
694 }
695}
696
697impl<'a> fmt::Display for ZString<'a> {
698 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699 write!(f, "{}", self.0)
700 }
701}
702
703impl<'a> ZString<'a> {
704 #[inline]
706 pub fn len(&self) -> usize {
707 self.0.len()
708 }
709
710 #[inline]
712 pub fn is_empty(&self) -> bool {
713 self.0.is_empty()
714 }
715
716 #[inline]
718 pub fn as_str(&self) -> &str {
719 self.0
720 }
721}
722
723#[derive(Debug, Clone, Copy, PartialEq)]
725pub enum ZRevert<'a> {
726 Error(ZString<'a>),
728 Panic(ZU256<'a>),
730 Custom(&'a [u8; 4], &'a [u8]),
732 Unknown,
734}
735
736impl<'a> fmt::Display for ZRevert<'a> {
737 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
738 match self {
739 ZRevert::Error(s) => write!(f, "Revert: {}", s.0),
740 ZRevert::Panic(p) => write!(f, "Panic: {}", p),
741 ZRevert::Custom(sel, _) => write!(
742 f,
743 "CustomError(0x{:02x}{:02x}{:02x}{:02x})",
744 sel[0], sel[1], sel[2], sel[3]
745 ),
746 ZRevert::Unknown => write!(f, "Unknown Revert"),
747 }
748 }
749}
750
751#[derive(Debug, Clone, Copy, PartialEq)]
753pub enum ZCallResult<'a, T> {
754 Success(T),
755 Revert(ZRevert<'a>),
756}
757
758impl<'a, T> ZCallResult<'a, T> {
759 pub fn is_success(&self) -> bool {
760 matches!(self, ZCallResult::Success(_))
761 }
762
763 pub fn is_revert(&self) -> bool {
764 matches!(self, ZCallResult::Revert(_))
765 }
766
767 pub fn unwrap(self) -> T {
768 match self {
769 ZCallResult::Success(val) => val,
770 ZCallResult::Revert(e) => panic!("Called unwrap on a Revert: {:?}", e),
771 }
772 }
773}