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