Skip to main content

bobcat_cd/
serialisation.rs

1use bobcat_maths::U;
2
3use bobcat_storage::{Keccak256, keccak256_builder};
4
5#[cfg(feature = "alloc")]
6extern crate alloc;
7
8#[cfg(feature = "alloc")]
9use alloc::{string::String, vec::Vec};
10
11#[cfg(not(feature = "std"))]
12mod no_std {
13    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
14    pub enum Error {
15        WriteAllEof,
16        ReadExactEof,
17        InvalidData,
18    }
19
20    pub trait Write {
21        fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
22        fn flush(&mut self) -> Result<(), Error>;
23        fn is_empty(&self) -> bool;
24
25        fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Error> {
26            while !buf.is_empty() {
27                match self.write(buf) {
28                    Ok(0) => return Err(Error::WriteAllEof),
29                    Ok(n) if n <= buf.len() => buf = &buf[n..],
30                    Ok(_) => return Err(Error::InvalidData),
31                    Err(error) => return Err(error),
32                }
33            }
34            Ok(())
35        }
36    }
37
38    pub trait Read {
39        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
40
41        fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Error> {
42            while !buf.is_empty() {
43                match self.read(buf) {
44                    Ok(0) => break,
45                    Ok(n) if n <= buf.len() => buf = &mut buf[n..],
46                    Ok(_) => return Err(Error::InvalidData),
47                    Err(error) => return Err(error),
48                }
49            }
50            if buf.is_empty() {
51                Ok(())
52            } else {
53                Err(Error::ReadExactEof)
54            }
55        }
56    }
57
58    impl Write for &mut [u8] {
59        fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
60            let len = core::cmp::min(self.len(), buf.len());
61            let target = core::mem::take(self);
62            let (written, remaining) = target.split_at_mut(len);
63            written.copy_from_slice(&buf[..len]);
64            *self = remaining;
65            Ok(len)
66        }
67
68        fn flush(&mut self) -> Result<(), Error> {
69            Ok(())
70        }
71
72        fn is_empty(&self) -> bool {
73            <[u8]>::is_empty(self)
74        }
75    }
76
77    impl Read for &[u8] {
78        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
79            let len = core::cmp::min(self.len(), buf.len());
80            buf[..len].copy_from_slice(&self[..len]);
81            *self = &self[len..];
82            Ok(len)
83        }
84    }
85}
86
87#[cfg(not(feature = "std"))]
88pub use no_std::{Error, Read, Write};
89
90#[cfg(feature = "std")]
91pub use std::io::{Error, Read, Write};
92
93#[doc(hidden)]
94#[derive(Clone)]
95pub struct SelectorHasher(Keccak256);
96
97impl SelectorHasher {
98    pub fn new() -> Self {
99        Self(keccak256_builder())
100    }
101
102    pub fn update(self, bytes: &[u8]) -> Self {
103        Self(self.0.update(bytes))
104    }
105
106    pub fn update_usize(self, mut value: usize) -> Self {
107        let mut digits = [0u8; 20];
108        let mut start = digits.len();
109        loop {
110            start -= 1;
111            digits[start] = b'0' + (value % 10) as u8;
112            value /= 10;
113            if value == 0 {
114                break;
115            }
116        }
117        self.update(&digits[start..])
118    }
119
120    pub fn selector(&self) -> [u8; 4] {
121        let hash = self.0.finalize();
122        [hash[0], hash[1], hash[2], hash[3]]
123    }
124}
125
126impl Default for SelectorHasher {
127    fn default() -> Self {
128        Self::new()
129    }
130}
131
132pub trait EvmCdSerialise {
133    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error>;
134
135    #[doc(hidden)]
136    fn serialise_value<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
137        self.serialise(writer)
138    }
139
140    #[doc(hidden)]
141    fn is_abi_dynamic() -> bool {
142        false
143    }
144
145    #[doc(hidden)]
146    fn abi_head_size() -> usize {
147        32
148    }
149
150    #[doc(hidden)]
151    fn abi_tail_size(&self) -> usize {
152        0
153    }
154
155    #[doc(hidden)]
156    fn serialise_abi_head<W: Write>(
157        &self,
158        _tail_offset: usize,
159        writer: &mut W,
160    ) -> Result<(), Error> {
161        self.serialise_value(writer)
162    }
163
164    #[doc(hidden)]
165    fn serialise_abi_tail<W: Write>(&self, _writer: &mut W) -> Result<(), Error> {
166        Ok(())
167    }
168
169    #[doc(hidden)]
170    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher;
171}
172
173#[doc(hidden)]
174pub enum EvmCdHead<T> {
175    Value(T),
176    Offset(usize),
177}
178
179#[doc(hidden)]
180pub struct EvmCdStaticBufferKind;
181
182#[cfg(feature = "alloc")]
183#[doc(hidden)]
184pub struct EvmCdDynamicBufferKind;
185
186#[doc(hidden)]
187pub trait EvmCdBufferKind {
188    type Buffer<S>: EvmCdDecodeBuffer;
189    type Combined<Rhs: EvmCdBufferKind>: EvmCdBufferKind;
190}
191
192impl EvmCdBufferKind for EvmCdStaticBufferKind {
193    type Buffer<S> = EvmCdBuffer<S>;
194    type Combined<Rhs: EvmCdBufferKind> = Rhs;
195}
196
197#[cfg(feature = "alloc")]
198impl EvmCdBufferKind for EvmCdDynamicBufferKind {
199    type Buffer<S> = EvmCdDynamicBuffer<S>;
200    type Combined<Rhs: EvmCdBufferKind> = EvmCdDynamicBufferKind;
201}
202
203#[doc(hidden)]
204pub trait EvmCdDecodeBuffer: AsRef<[u8]> + AsMut<[u8]> + Sized {
205    type Kind: EvmCdBufferKind;
206
207    fn new(len: usize) -> Result<Self, Error>;
208}
209
210#[doc(hidden)]
211pub struct EvmCdBuffer<S> {
212    storage: core::mem::MaybeUninit<S>,
213}
214
215impl<S> EvmCdDecodeBuffer for EvmCdBuffer<S> {
216    type Kind = EvmCdStaticBufferKind;
217
218    fn new(len: usize) -> Result<Self, Error> {
219        if len > size_of::<S>() {
220            return Err(invalid_data());
221        }
222        let mut storage = core::mem::MaybeUninit::<S>::uninit();
223        // SAFETY: the storage remains wrapped in MaybeUninit and is only exposed as bytes.
224        // Zeroing every byte makes the complete u8 slice valid without constructing an S.
225        unsafe {
226            storage
227                .as_mut_ptr()
228                .cast::<u8>()
229                .write_bytes(0, size_of::<S>())
230        };
231        Ok(Self { storage })
232    }
233}
234
235impl<S> AsRef<[u8]> for EvmCdBuffer<S> {
236    fn as_ref(&self) -> &[u8] {
237        // SAFETY: new() zero-initializes every byte before constructing Self.
238        unsafe { core::slice::from_raw_parts(self.storage.as_ptr().cast::<u8>(), size_of::<S>()) }
239    }
240}
241
242impl<S> AsMut<[u8]> for EvmCdBuffer<S> {
243    fn as_mut(&mut self) -> &mut [u8] {
244        // SAFETY: new() zero-initializes every byte before constructing Self.
245        unsafe {
246            core::slice::from_raw_parts_mut(self.storage.as_mut_ptr().cast::<u8>(), size_of::<S>())
247        }
248    }
249}
250
251#[cfg(feature = "alloc")]
252#[doc(hidden)]
253pub struct EvmCdDynamicBuffer<S>(Vec<u8>, core::marker::PhantomData<S>);
254
255#[cfg(feature = "alloc")]
256impl<S> EvmCdDecodeBuffer for EvmCdDynamicBuffer<S> {
257    type Kind = EvmCdDynamicBufferKind;
258
259    fn new(len: usize) -> Result<Self, Error> {
260        if len > MAX_ALLOC_DESERIALISE_LEN {
261            return Err(invalid_data());
262        }
263        let mut bytes = Vec::new();
264        bytes.try_reserve_exact(len).map_err(|_| invalid_data())?;
265        bytes.resize(len, 0);
266        Ok(Self(bytes, core::marker::PhantomData))
267    }
268}
269
270#[cfg(feature = "alloc")]
271impl<S> AsRef<[u8]> for EvmCdDynamicBuffer<S> {
272    fn as_ref(&self) -> &[u8] {
273        &self.0
274    }
275}
276
277#[cfg(feature = "alloc")]
278impl<S> AsMut<[u8]> for EvmCdDynamicBuffer<S> {
279    fn as_mut(&mut self) -> &mut [u8] {
280        &mut self.0
281    }
282}
283
284pub trait EvmCdDeserialise: Sized {
285    type Buffer: EvmCdDecodeBuffer;
286
287    fn new_buffer(len: usize) -> Result<Self::Buffer, Error> {
288        Self::Buffer::new(len)
289    }
290
291    fn deserialise<B>(bytes: &B) -> Result<Self, Error>
292    where
293        B: AsRef<[u8]> + ?Sized,
294    {
295        let mut reader = bytes.as_ref();
296        Self::deserialise_reader(&mut reader)
297    }
298
299    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error>;
300
301    #[doc(hidden)]
302    fn deserialise_value<R: Read>(reader: &mut R) -> Result<Self, Error> {
303        Self::deserialise_reader(reader)
304    }
305
306    #[doc(hidden)]
307    fn is_abi_dynamic() -> bool {
308        false
309    }
310
311    #[doc(hidden)]
312    fn abi_head_size() -> usize {
313        32
314    }
315
316    #[doc(hidden)]
317    fn abi_tail_size(&self) -> usize {
318        0
319    }
320
321    #[doc(hidden)]
322    fn deserialise_abi_head<R: Read>(reader: &mut R) -> Result<EvmCdHead<Self>, Error> {
323        Ok(EvmCdHead::Value(Self::deserialise_value(reader)?))
324    }
325
326    #[doc(hidden)]
327    fn deserialise_abi_finish<R: Read>(
328        head: EvmCdHead<Self>,
329        _expected_tail_offset: usize,
330        _reader: &mut R,
331    ) -> Result<Self, Error> {
332        match head {
333            EvmCdHead::Value(value) => Ok(value),
334            EvmCdHead::Offset(_) => Err(invalid_data()),
335        }
336    }
337
338    #[doc(hidden)]
339    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher;
340}
341
342#[cfg(not(feature = "std"))]
343pub fn invalid_data() -> Error {
344    Error::InvalidData
345}
346
347#[cfg(feature = "std")]
348pub fn invalid_data() -> Error {
349    Error::new(std::io::ErrorKind::InvalidData, "invalid EVM calldata")
350}
351
352fn read_usize_word<R: Read>(reader: &mut R) -> Result<usize, Error> {
353    let mut word = [0u8; 32];
354    reader.read_exact(&mut word)?;
355    if word[..32 - size_of::<usize>()]
356        .iter()
357        .any(|byte| *byte != 0)
358    {
359        return Err(invalid_data());
360    }
361    Ok(usize::from_be_bytes(
362        word[32 - size_of::<usize>()..].try_into().unwrap(),
363    ))
364}
365
366fn write_dynamic_tail<W: Write>(bytes: &[u8], writer: &mut W) -> Result<(), Error> {
367    writer.write_all(&U::from_usize(bytes.len()).0)?;
368    writer.write_all(bytes)?;
369    const ZEROES: [u8; 31] = [0; 31];
370    let padding = (32 - bytes.len() % 32) % 32;
371    writer.write_all(&ZEROES[..padding])
372}
373
374fn write_dynamic_bytes<W: Write>(bytes: &[u8], writer: &mut W) -> Result<(), Error> {
375    writer.write_all(&U::from_u32(32).0)?;
376    write_dynamic_tail(bytes, writer)
377}
378
379fn dynamic_tail_size(len: usize) -> usize {
380    32 + len + (32 - len % 32) % 32
381}
382
383fn read_dynamic_tail<const CAP: usize, R: Read>(
384    reader: &mut R,
385) -> Result<([u8; CAP], usize), Error> {
386    let len = read_usize_word(reader)?;
387    if len > CAP {
388        return Err(invalid_data());
389    }
390    let mut bytes = [0u8; CAP];
391    reader.read_exact(&mut bytes[..len])?;
392    let padding = (32 - len % 32) % 32;
393    let mut padding_bytes = [0u8; 31];
394    reader.read_exact(&mut padding_bytes[..padding])?;
395    if padding_bytes[..padding].iter().any(|byte| *byte != 0) {
396        return Err(invalid_data());
397    }
398    Ok((bytes, len))
399}
400
401fn read_dynamic_bytes<const CAP: usize, R: Read>(
402    reader: &mut R,
403) -> Result<([u8; CAP], usize), Error> {
404    if read_usize_word(reader)? != 32 {
405        return Err(invalid_data());
406    }
407    read_dynamic_tail(reader)
408}
409
410macro_rules! fixed_deserialise_buffer {
411    ($storage:ty) => {
412        type Buffer = EvmCdBuffer<$storage>;
413    };
414}
415
416impl EvmCdSerialise for U {
417    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
418        writer.write_all(&self.0)
419    }
420
421    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
422        hasher.update(b"uint256")
423    }
424}
425
426impl EvmCdDeserialise for U {
427    fixed_deserialise_buffer!([u8; 32]);
428
429    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
430        let mut buf = [0u8; 32];
431        reader.read_exact(&mut buf)?;
432        Ok(U(buf))
433    }
434
435    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
436        hasher.update(b"uint256")
437    }
438}
439
440macro_rules! for_ints {
441    ($($ty:ty => $abi:literal),+ $(,)?) => {
442        $(
443            impl EvmCdSerialise for $ty {
444                fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
445                    writer.write_all(&[0u8; 32 - size_of::<$ty>()])?;
446                    writer.write_all(&self.to_be_bytes())
447                }
448
449                fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
450                    hasher.update($abi)
451                }
452            }
453
454            impl EvmCdDeserialise for $ty {
455                fixed_deserialise_buffer!([u8; 32]);
456
457                fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
458                    let U(word) = U::deserialise_reader(reader)?;
459                    if word[..32 - size_of::<$ty>()].iter().any(|byte| *byte != 0) {
460                        return Err(invalid_data());
461                    }
462                    Ok(<$ty>::from_be_bytes(
463                        word[32 - size_of::<$ty>()..].try_into().unwrap(),
464                    ))
465                }
466
467                fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
468                    hasher.update($abi)
469                }
470            }
471        )+
472    };
473}
474
475for_ints! {
476    u8 => b"uint8",
477    u16 => b"uint16",
478    u32 => b"uint32",
479    u64 => b"uint64",
480    u128 => b"uint128",
481}
482
483impl EvmCdSerialise for usize {
484    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
485        u32::try_from(*self)
486            .map_err(|_| invalid_data())?
487            .serialise(writer)
488    }
489
490    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
491        hasher.update(b"uint32")
492    }
493}
494
495impl EvmCdDeserialise for usize {
496    fixed_deserialise_buffer!([u8; 32]);
497
498    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
499        Ok(u32::deserialise_reader(reader)? as usize)
500    }
501
502    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
503        hasher.update(b"uint32")
504    }
505}
506
507#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
508pub struct EvmCdAddress([u8; 20]);
509
510impl EvmCdAddress {
511    pub const fn new(bytes: [u8; 20]) -> Self {
512        Self(bytes)
513    }
514
515    pub const fn into_array(self) -> [u8; 20] {
516        self.0
517    }
518
519    pub const fn as_array(&self) -> &[u8; 20] {
520        &self.0
521    }
522}
523
524impl From<[u8; 20]> for EvmCdAddress {
525    fn from(bytes: [u8; 20]) -> Self {
526        Self::new(bytes)
527    }
528}
529
530impl From<EvmCdAddress> for [u8; 20] {
531    fn from(address: EvmCdAddress) -> Self {
532        address.into_array()
533    }
534}
535
536impl AsRef<[u8; 20]> for EvmCdAddress {
537    fn as_ref(&self) -> &[u8; 20] {
538        self.as_array()
539    }
540}
541
542impl AsRef<[u8]> for EvmCdAddress {
543    fn as_ref(&self) -> &[u8] {
544        self.as_array()
545    }
546}
547
548impl EvmCdSerialise for EvmCdAddress {
549    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
550        writer.write_all(&[0; 12])?;
551        writer.write_all(&self.0)
552    }
553
554    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
555        hasher.update(b"address")
556    }
557}
558
559impl EvmCdDeserialise for EvmCdAddress {
560    fixed_deserialise_buffer!([u8; 32]);
561
562    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
563        let mut word = [0u8; 32];
564        reader.read_exact(&mut word)?;
565        if word[..12].iter().any(|byte| *byte != 0) {
566            return Err(invalid_data());
567        }
568        Ok(Self(word[12..].try_into().unwrap()))
569    }
570
571    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
572        hasher.update(b"address")
573    }
574}
575
576impl<const N: usize> EvmCdSerialise for [u8; N] {
577    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
578        if N == 0 || N > 32 {
579            return Err(invalid_data());
580        }
581        writer.write_all(self)?;
582        const ZEROES: [u8; 32] = [0; 32];
583        writer.write_all(&ZEROES[..32 - N])
584    }
585
586    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
587        hasher.update(b"bytes").update_usize(N)
588    }
589}
590
591impl<const N: usize> EvmCdDeserialise for [u8; N] {
592    fixed_deserialise_buffer!([u8; 32]);
593
594    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
595        if N == 0 || N > 32 {
596            return Err(invalid_data());
597        }
598        let mut word = [0u8; 32];
599        reader.read_exact(&mut word)?;
600        if word[N..].iter().any(|byte| *byte != 0) {
601            return Err(invalid_data());
602        }
603        Ok(word[..N].try_into().unwrap())
604    }
605
606    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
607        hasher.update(b"bytes").update_usize(N)
608    }
609}
610
611#[derive(Debug, Clone, Copy, PartialEq, Eq)]
612pub enum EvmCdArrayError {
613    InvalidBounds,
614    TooShort,
615    TooLong,
616}
617
618pub struct EvmCdArray<T, const MIN: usize, const CAP: usize> {
619    len: usize,
620    values: [core::mem::MaybeUninit<T>; CAP],
621}
622
623impl<T, const MIN: usize, const CAP: usize> EvmCdArray<T, MIN, CAP> {
624    fn empty() -> Self {
625        Self {
626            len: 0,
627            values: [const { core::mem::MaybeUninit::uninit() }; CAP],
628        }
629    }
630
631    fn validate_len(len: usize) -> Result<(), EvmCdArrayError> {
632        if MIN > CAP {
633            return Err(EvmCdArrayError::InvalidBounds);
634        }
635        if len < MIN {
636            return Err(EvmCdArrayError::TooShort);
637        }
638        if len > CAP {
639            return Err(EvmCdArrayError::TooLong);
640        }
641        Ok(())
642    }
643
644    fn push(&mut self, value: T) {
645        debug_assert!(self.len < CAP);
646        self.values[self.len].write(value);
647        self.len += 1;
648    }
649
650    pub fn try_from_array(values: [T; CAP], len: usize) -> Result<Self, EvmCdArrayError> {
651        Self::validate_len(len)?;
652        let mut out = Self::empty();
653        for value in values.into_iter().take(len) {
654            out.push(value);
655        }
656        Ok(out)
657    }
658
659    pub fn try_from_slice(values: &[T]) -> Result<Self, EvmCdArrayError>
660    where
661        T: Clone,
662    {
663        Self::validate_len(values.len())?;
664        let mut out = Self::empty();
665        for value in values {
666            out.push(value.clone());
667        }
668        Ok(out)
669    }
670
671    pub const fn len(&self) -> usize {
672        self.len
673    }
674
675    pub const fn is_empty(&self) -> bool {
676        self.len == 0
677    }
678
679    pub const fn capacity(&self) -> usize {
680        CAP
681    }
682
683    pub fn as_slice(&self) -> &[T] {
684        // SAFETY: the first `len` slots are initialized by every constructor
685        // and `push`, and `len` can never exceed CAP.
686        unsafe { core::slice::from_raw_parts(self.values.as_ptr().cast::<T>(), self.len) }
687    }
688}
689
690impl<T, const MIN: usize, const CAP: usize> Drop for EvmCdArray<T, MIN, CAP> {
691    fn drop(&mut self) {
692        for value in &mut self.values[..self.len] {
693            // SAFETY: exactly the first `len` slots are initialized.
694            unsafe { value.assume_init_drop() };
695        }
696    }
697}
698
699impl<T: Clone, const MIN: usize, const CAP: usize> Clone for EvmCdArray<T, MIN, CAP> {
700    fn clone(&self) -> Self {
701        Self::try_from_slice(self.as_slice()).expect("an existing EvmCdArray has valid bounds")
702    }
703}
704
705impl<T: core::fmt::Debug, const MIN: usize, const CAP: usize> core::fmt::Debug
706    for EvmCdArray<T, MIN, CAP>
707{
708    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
709        formatter.debug_list().entries(self.as_slice()).finish()
710    }
711}
712
713impl<T: PartialEq, const MIN: usize, const CAP: usize> PartialEq for EvmCdArray<T, MIN, CAP> {
714    fn eq(&self, other: &Self) -> bool {
715        self.as_slice() == other.as_slice()
716    }
717}
718
719impl<T: Eq, const MIN: usize, const CAP: usize> Eq for EvmCdArray<T, MIN, CAP> {}
720
721impl<T, const MIN: usize, const CAP: usize> AsRef<[T]> for EvmCdArray<T, MIN, CAP> {
722    fn as_ref(&self) -> &[T] {
723        self.as_slice()
724    }
725}
726
727impl<T, const MIN: usize, const CAP: usize> EvmCdSerialise for EvmCdArray<T, MIN, CAP>
728where
729    T: EvmCdSerialise,
730{
731    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
732        U::from_u32(32).serialise_value(writer)?;
733        self.serialise_abi_tail(writer)
734    }
735
736    fn is_abi_dynamic() -> bool {
737        true
738    }
739
740    fn abi_tail_size(&self) -> usize {
741        self.len
742            .saturating_mul(T::abi_head_size())
743            .saturating_add(32)
744            .saturating_add(self.as_slice().iter().fold(0usize, |size, value| {
745                size.saturating_add(value.abi_tail_size())
746            }))
747    }
748
749    fn serialise_abi_head<W: Write>(
750        &self,
751        tail_offset: usize,
752        writer: &mut W,
753    ) -> Result<(), Error> {
754        U::from_usize(tail_offset).serialise_value(writer)
755    }
756
757    fn serialise_abi_tail<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
758        U::from_usize(self.len).serialise_value(writer)?;
759        let mut tail_offset = self
760            .len
761            .checked_mul(T::abi_head_size())
762            .ok_or_else(invalid_data)?;
763        for value in self.as_slice() {
764            value.serialise_abi_head(tail_offset, writer)?;
765            tail_offset = tail_offset
766                .checked_add(value.abi_tail_size())
767                .ok_or_else(invalid_data)?;
768        }
769        for value in self.as_slice() {
770            value.serialise_abi_tail(writer)?;
771        }
772        Ok(())
773    }
774
775    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
776        T::append_abi_type(hasher).update(b"[]")
777    }
778}
779
780impl<T, const MIN: usize, const CAP: usize> EvmCdDeserialise for EvmCdArray<T, MIN, CAP>
781where
782    T: EvmCdDeserialise,
783{
784    type Buffer = <<T::Buffer as EvmCdDecodeBuffer>::Kind as EvmCdBufferKind>::Buffer<(
785        [u8; 64],
786        [T::Buffer; CAP],
787    )>;
788
789    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
790        if read_usize_word(reader)? != 32 {
791            return Err(invalid_data());
792        }
793        Self::deserialise_tail(reader)
794    }
795
796    fn is_abi_dynamic() -> bool {
797        true
798    }
799
800    fn abi_tail_size(&self) -> usize {
801        self.len
802            .saturating_mul(T::abi_head_size())
803            .saturating_add(32)
804            .saturating_add(self.as_slice().iter().fold(0usize, |size, value| {
805                size.saturating_add(value.abi_tail_size())
806            }))
807    }
808
809    fn deserialise_abi_head<R: Read>(reader: &mut R) -> Result<EvmCdHead<Self>, Error> {
810        Ok(EvmCdHead::Offset(read_usize_word(reader)?))
811    }
812
813    fn deserialise_abi_finish<R: Read>(
814        head: EvmCdHead<Self>,
815        expected_tail_offset: usize,
816        reader: &mut R,
817    ) -> Result<Self, Error> {
818        match head {
819            EvmCdHead::Offset(offset) if offset == expected_tail_offset => {
820                Self::deserialise_tail(reader)
821            }
822            _ => Err(invalid_data()),
823        }
824    }
825
826    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
827        T::append_abi_type(hasher).update(b"[]")
828    }
829}
830
831impl<T, const MIN: usize, const CAP: usize> EvmCdArray<T, MIN, CAP>
832where
833    T: EvmCdDeserialise,
834{
835    fn deserialise_tail<R: Read>(reader: &mut R) -> Result<Self, Error> {
836        let len = read_usize_word(reader)?;
837        Self::validate_len(len).map_err(|_| invalid_data())?;
838        let mut out = Self::empty();
839
840        if T::is_abi_dynamic() {
841            let mut offsets = [0usize; CAP];
842            for offset in &mut offsets[..len] {
843                match T::deserialise_abi_head(reader)? {
844                    EvmCdHead::Offset(value) => *offset = value,
845                    EvmCdHead::Value(_) => return Err(invalid_data()),
846                }
847            }
848            let mut expected_tail_offset = len
849                .checked_mul(T::abi_head_size())
850                .ok_or_else(invalid_data)?;
851            for offset in offsets[..len].iter().copied() {
852                let value = T::deserialise_abi_finish(
853                    EvmCdHead::Offset(offset),
854                    expected_tail_offset,
855                    reader,
856                )?;
857                expected_tail_offset = expected_tail_offset
858                    .checked_add(value.abi_tail_size())
859                    .ok_or_else(invalid_data)?;
860                out.push(value);
861            }
862        } else {
863            for _ in 0..len {
864                let head = T::deserialise_abi_head(reader)?;
865                out.push(T::deserialise_abi_finish(head, 0, reader)?);
866            }
867        }
868        Ok(out)
869    }
870}
871
872#[derive(Debug, Clone, Copy, PartialEq, Eq)]
873pub enum EvmCdStringError {
874    InvalidBounds,
875    TooShort,
876    TooLong,
877}
878
879#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
880pub struct EvmCdString<const MIN: usize, const CAP: usize> {
881    len: usize,
882    bytes: [u8; CAP],
883}
884
885impl<const MIN: usize, const CAP: usize> EvmCdString<MIN, CAP> {
886    pub fn try_from_str(value: &str) -> Result<Self, EvmCdStringError> {
887        if MIN > CAP {
888            return Err(EvmCdStringError::InvalidBounds);
889        }
890        if value.len() < MIN {
891            return Err(EvmCdStringError::TooShort);
892        }
893        if value.len() > CAP {
894            return Err(EvmCdStringError::TooLong);
895        }
896        let mut bytes = [0u8; CAP];
897        bytes[..value.len()].copy_from_slice(value.as_bytes());
898        Ok(Self {
899            len: value.len(),
900            bytes,
901        })
902    }
903
904    pub const fn len(&self) -> usize {
905        self.len
906    }
907
908    pub const fn is_empty(&self) -> bool {
909        self.len == 0
910    }
911
912    pub const fn capacity(&self) -> usize {
913        CAP
914    }
915
916    pub fn as_bytes(&self) -> &[u8] {
917        &self.bytes[..self.len]
918    }
919
920    pub fn as_str(&self) -> &str {
921        // SAFETY: constructors and deserialisation validate UTF-8, and no API
922        // exposes mutable access to the initialized bytes.
923        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
924    }
925}
926
927impl<const MIN: usize, const CAP: usize> TryFrom<&str> for EvmCdString<MIN, CAP> {
928    type Error = EvmCdStringError;
929
930    fn try_from(value: &str) -> Result<Self, Self::Error> {
931        Self::try_from_str(value)
932    }
933}
934
935impl<const MIN: usize, const CAP: usize> AsRef<str> for EvmCdString<MIN, CAP> {
936    fn as_ref(&self) -> &str {
937        self.as_str()
938    }
939}
940
941impl<const MIN: usize, const CAP: usize> AsRef<[u8]> for EvmCdString<MIN, CAP> {
942    fn as_ref(&self) -> &[u8] {
943        self.as_bytes()
944    }
945}
946
947impl<const MIN: usize, const CAP: usize> core::borrow::Borrow<str> for EvmCdString<MIN, CAP> {
948    fn borrow(&self) -> &str {
949        self.as_str()
950    }
951}
952
953impl<const MIN: usize, const CAP: usize> core::fmt::Display for EvmCdString<MIN, CAP> {
954    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
955        formatter.write_str(self.as_str())
956    }
957}
958
959impl<const MIN: usize, const CAP: usize> core::fmt::Debug for EvmCdString<MIN, CAP> {
960    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
961        core::fmt::Debug::fmt(self.as_str(), formatter)
962    }
963}
964
965impl<const MIN: usize, const CAP: usize> core::str::FromStr for EvmCdString<MIN, CAP> {
966    type Err = EvmCdStringError;
967
968    fn from_str(value: &str) -> Result<Self, Self::Err> {
969        Self::try_from_str(value)
970    }
971}
972
973impl<const MIN: usize, const CAP: usize> EvmCdSerialise for EvmCdString<MIN, CAP> {
974    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
975        write_dynamic_bytes(self.as_bytes(), writer)
976    }
977
978    fn is_abi_dynamic() -> bool {
979        true
980    }
981
982    fn abi_tail_size(&self) -> usize {
983        dynamic_tail_size(self.len)
984    }
985
986    fn serialise_abi_head<W: Write>(
987        &self,
988        tail_offset: usize,
989        writer: &mut W,
990    ) -> Result<(), Error> {
991        U::from_usize(tail_offset).serialise_value(writer)
992    }
993
994    fn serialise_abi_tail<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
995        write_dynamic_tail(self.as_bytes(), writer)
996    }
997
998    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
999        hasher.update(b"string")
1000    }
1001}
1002
1003impl<const MIN: usize, const CAP: usize> EvmCdDeserialise for EvmCdString<MIN, CAP> {
1004    type Buffer = EvmCdBuffer<([u8; 64], [u8; CAP], [u8; 31])>;
1005
1006    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
1007        if MIN > CAP {
1008            return Err(invalid_data());
1009        }
1010        let (bytes, len) = read_dynamic_bytes::<CAP, _>(reader)?;
1011        if len < MIN || core::str::from_utf8(&bytes[..len]).is_err() {
1012            return Err(invalid_data());
1013        }
1014        Ok(Self { len, bytes })
1015    }
1016
1017    fn is_abi_dynamic() -> bool {
1018        true
1019    }
1020
1021    fn abi_tail_size(&self) -> usize {
1022        dynamic_tail_size(self.len)
1023    }
1024
1025    fn deserialise_abi_head<R: Read>(reader: &mut R) -> Result<EvmCdHead<Self>, Error> {
1026        Ok(EvmCdHead::Offset(read_usize_word(reader)?))
1027    }
1028
1029    fn deserialise_abi_finish<R: Read>(
1030        head: EvmCdHead<Self>,
1031        expected_tail_offset: usize,
1032        reader: &mut R,
1033    ) -> Result<Self, Error> {
1034        match head {
1035            EvmCdHead::Offset(offset) if offset == expected_tail_offset => {
1036                if MIN > CAP {
1037                    return Err(invalid_data());
1038                }
1039                let (bytes, len) = read_dynamic_tail::<CAP, _>(reader)?;
1040                if len < MIN || core::str::from_utf8(&bytes[..len]).is_err() {
1041                    return Err(invalid_data());
1042                }
1043                Ok(Self { len, bytes })
1044            }
1045            _ => Err(invalid_data()),
1046        }
1047    }
1048
1049    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
1050        hasher.update(b"string")
1051    }
1052}
1053
1054#[cfg(feature = "alloc")]
1055impl<const MIN: usize, const CAP: usize> From<EvmCdString<MIN, CAP>> for String {
1056    fn from(value: EvmCdString<MIN, CAP>) -> Self {
1057        String::from(value.as_str())
1058    }
1059}
1060
1061#[cfg(feature = "alloc")]
1062fn vec_is_bytes<T: 'static>() -> bool {
1063    core::any::TypeId::of::<T>() == core::any::TypeId::of::<u8>()
1064}
1065
1066#[cfg(feature = "alloc")]
1067fn vec_as_bytes<T: 'static>(values: &[T]) -> &[u8] {
1068    debug_assert!(vec_is_bytes::<T>());
1069    // SAFETY: this helper is called only when TypeId proves that T is u8.
1070    unsafe { core::slice::from_raw_parts(values.as_ptr().cast::<u8>(), values.len()) }
1071}
1072
1073#[cfg(feature = "alloc")]
1074impl<T> EvmCdSerialise for Vec<T>
1075where
1076    T: EvmCdSerialise + 'static,
1077{
1078    fn serialise<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
1079        U::from_u32(32).serialise_value(writer)?;
1080        self.serialise_abi_tail(writer)
1081    }
1082
1083    fn is_abi_dynamic() -> bool {
1084        true
1085    }
1086
1087    fn abi_tail_size(&self) -> usize {
1088        if vec_is_bytes::<T>() {
1089            dynamic_tail_size(self.len())
1090        } else {
1091            self.len()
1092                .saturating_mul(T::abi_head_size())
1093                .saturating_add(32)
1094                .saturating_add(self.iter().fold(0usize, |size, value| {
1095                    size.saturating_add(value.abi_tail_size())
1096                }))
1097        }
1098    }
1099
1100    fn serialise_abi_head<W: Write>(
1101        &self,
1102        tail_offset: usize,
1103        writer: &mut W,
1104    ) -> Result<(), Error> {
1105        U::from_usize(tail_offset).serialise_value(writer)
1106    }
1107
1108    fn serialise_abi_tail<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
1109        if vec_is_bytes::<T>() {
1110            return write_dynamic_tail(vec_as_bytes(self), writer);
1111        }
1112
1113        U::from_usize(self.len()).serialise_value(writer)?;
1114        let mut tail_offset = self
1115            .len()
1116            .checked_mul(T::abi_head_size())
1117            .ok_or_else(invalid_data)?;
1118        for value in self {
1119            value.serialise_abi_head(tail_offset, writer)?;
1120            tail_offset = tail_offset
1121                .checked_add(value.abi_tail_size())
1122                .ok_or_else(invalid_data)?;
1123        }
1124        for value in self {
1125            value.serialise_abi_tail(writer)?;
1126        }
1127        Ok(())
1128    }
1129
1130    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
1131        if vec_is_bytes::<T>() {
1132            hasher.update(b"bytes")
1133        } else {
1134            T::append_abi_type(hasher).update(b"[]")
1135        }
1136    }
1137}
1138
1139#[cfg(feature = "alloc")]
1140const MAX_ALLOC_DESERIALISE_LEN: usize = 16 * 1024 * 1024;
1141
1142#[cfg(feature = "alloc")]
1143fn read_vec_bytes_tail<R: Read>(reader: &mut R) -> Result<Vec<u8>, Error> {
1144    let len = read_usize_word(reader)?;
1145    if len > MAX_ALLOC_DESERIALISE_LEN {
1146        return Err(invalid_data());
1147    }
1148    let mut out = Vec::new();
1149    out.try_reserve_exact(len).map_err(|_| invalid_data())?;
1150    out.resize(len, 0);
1151    reader.read_exact(&mut out)?;
1152    let padding = (32 - len % 32) % 32;
1153    let mut padding_bytes = [0u8; 31];
1154    reader.read_exact(&mut padding_bytes[..padding])?;
1155    if padding_bytes[..padding].iter().any(|byte| *byte != 0) {
1156        return Err(invalid_data());
1157    }
1158    Ok(out)
1159}
1160
1161#[cfg(feature = "alloc")]
1162fn bytes_into_vec<T: 'static>(bytes: Vec<u8>) -> Vec<T> {
1163    debug_assert!(vec_is_bytes::<T>());
1164    let mut bytes = core::mem::ManuallyDrop::new(bytes);
1165    // SAFETY: TypeId proves that T is u8, so the allocation layout and elements match.
1166    unsafe {
1167        Vec::from_raw_parts(
1168            bytes.as_mut_ptr().cast::<T>(),
1169            bytes.len(),
1170            bytes.capacity(),
1171        )
1172    }
1173}
1174
1175#[cfg(feature = "alloc")]
1176fn validate_vec_array_len<T: EvmCdDeserialise>(len: usize) -> Result<(), Error> {
1177    let head_bytes = len
1178        .checked_mul(T::abi_head_size())
1179        .ok_or_else(invalid_data)?;
1180    let value_bytes = len
1181        .checked_mul(core::mem::size_of::<T>())
1182        .ok_or_else(invalid_data)?;
1183    let offset_bytes = if T::is_abi_dynamic() {
1184        len.checked_mul(core::mem::size_of::<usize>())
1185            .ok_or_else(invalid_data)?
1186    } else {
1187        0
1188    };
1189    if head_bytes > MAX_ALLOC_DESERIALISE_LEN
1190        || value_bytes > MAX_ALLOC_DESERIALISE_LEN
1191        || offset_bytes > MAX_ALLOC_DESERIALISE_LEN
1192    {
1193        return Err(invalid_data());
1194    }
1195    Ok(())
1196}
1197
1198#[cfg(feature = "alloc")]
1199fn read_vec_array_tail<T, R>(reader: &mut R) -> Result<Vec<T>, Error>
1200where
1201    T: EvmCdDeserialise + 'static,
1202    R: Read,
1203{
1204    let len = read_usize_word(reader)?;
1205    validate_vec_array_len::<T>(len)?;
1206
1207    let mut out = Vec::new();
1208    out.try_reserve_exact(len).map_err(|_| invalid_data())?;
1209    if T::is_abi_dynamic() {
1210        let mut offsets = Vec::new();
1211        offsets.try_reserve_exact(len).map_err(|_| invalid_data())?;
1212        for _ in 0..len {
1213            match T::deserialise_abi_head(reader)? {
1214                EvmCdHead::Offset(offset) => offsets.push(offset),
1215                EvmCdHead::Value(_) => return Err(invalid_data()),
1216            }
1217        }
1218        let mut expected_tail_offset = len
1219            .checked_mul(T::abi_head_size())
1220            .ok_or_else(invalid_data)?;
1221        for offset in offsets {
1222            let value =
1223                T::deserialise_abi_finish(EvmCdHead::Offset(offset), expected_tail_offset, reader)?;
1224            expected_tail_offset = expected_tail_offset
1225                .checked_add(value.abi_tail_size())
1226                .ok_or_else(invalid_data)?;
1227            out.push(value);
1228        }
1229    } else {
1230        for _ in 0..len {
1231            let head = T::deserialise_abi_head(reader)?;
1232            out.push(T::deserialise_abi_finish(head, 0, reader)?);
1233        }
1234    }
1235    Ok(out)
1236}
1237
1238#[cfg(feature = "alloc")]
1239fn read_vec_tail<T, R>(reader: &mut R) -> Result<Vec<T>, Error>
1240where
1241    T: EvmCdDeserialise + 'static,
1242    R: Read,
1243{
1244    if vec_is_bytes::<T>() {
1245        read_vec_bytes_tail(reader).map(bytes_into_vec)
1246    } else {
1247        read_vec_array_tail(reader)
1248    }
1249}
1250
1251#[cfg(feature = "alloc")]
1252impl<T> EvmCdDeserialise for Vec<T>
1253where
1254    T: EvmCdDeserialise + 'static,
1255{
1256    type Buffer = EvmCdDynamicBuffer<()>;
1257
1258    fn deserialise_reader<R: Read>(reader: &mut R) -> Result<Self, Error> {
1259        if read_usize_word(reader)? != 32 {
1260            return Err(invalid_data());
1261        }
1262        read_vec_tail(reader)
1263    }
1264
1265    fn is_abi_dynamic() -> bool {
1266        true
1267    }
1268
1269    fn abi_tail_size(&self) -> usize {
1270        if vec_is_bytes::<T>() {
1271            dynamic_tail_size(self.len())
1272        } else {
1273            self.len()
1274                .saturating_mul(T::abi_head_size())
1275                .saturating_add(32)
1276                .saturating_add(self.iter().fold(0usize, |size, value| {
1277                    size.saturating_add(value.abi_tail_size())
1278                }))
1279        }
1280    }
1281
1282    fn deserialise_abi_head<R: Read>(reader: &mut R) -> Result<EvmCdHead<Self>, Error> {
1283        Ok(EvmCdHead::Offset(read_usize_word(reader)?))
1284    }
1285
1286    fn deserialise_abi_finish<R: Read>(
1287        head: EvmCdHead<Self>,
1288        expected_tail_offset: usize,
1289        reader: &mut R,
1290    ) -> Result<Self, Error> {
1291        match head {
1292            EvmCdHead::Offset(offset) if offset == expected_tail_offset => read_vec_tail(reader),
1293            _ => Err(invalid_data()),
1294        }
1295    }
1296
1297    fn append_abi_type(hasher: SelectorHasher) -> SelectorHasher {
1298        if vec_is_bytes::<T>() {
1299            hasher.update(b"bytes")
1300        } else {
1301            T::append_abi_type(hasher).update(b"[]")
1302        }
1303    }
1304}