starknet_core/
codec.rs

1use alloc::{boxed::Box, fmt::Formatter, format, string::*, vec::*};
2use core::{fmt::Display, mem::MaybeUninit};
3use starknet_crypto::{PedersenHasher, PoseidonHasher};
4
5use num_traits::ToPrimitive;
6
7use crate::types::{Felt, U256};
8
9pub use starknet_core_derive::{Decode, Encode};
10
11const I128_MIN: Felt =
12    Felt::from_hex_unchecked("0x0800000000000010ffffffffffffffff80000000000000000000000000000001");
13const I128_MAX: Felt =
14    Felt::from_hex_unchecked("0x000000000000000000000000000000007fffffffffffffffffffffffffffffff");
15
16/// Any type where [`Felt`]s can be written into. This would typically be [`Vec<Felt>`], but can
17/// also be something like a stateful hasher.
18///
19/// The trait method is infallible, as the most common use case is to simply write into a `Vec`.
20/// Making the method infallible avoids over-engineering. However, if deemed necessary, a future
21/// breaking change can make this fallible instead.
22pub trait FeltWriter {
23    /// Adds a single [Felt] element into the writer.
24    fn write(&mut self, felt: Felt);
25}
26
27/// Any type that can be serialized into a series of [Felt]s. This trait corresponds to the
28/// `serialize` function of the Cairo `Serde` trait.
29///
30/// This trait can be derived as long as all the fields in type implement [`Encode`].
31///
32/// # Example
33///
34/// This example demonstrates deriving the trait and then using it to serialize an instance into
35/// [`Vec<Felt>`].
36///
37/// ```rust
38/// use starknet_core::codec::Encode;
39/// # use starknet_core::types::Felt;
40///
41/// #[derive(Encode)]
42/// # #[starknet(core = "starknet_core")]
43/// struct CairoType {
44///     a: u32,
45///     b: Option<bool>,
46/// }
47///
48/// let instance = CairoType {
49///     a: 3,
50///     b: Some(true),
51/// };
52/// let mut serialized = vec![];
53/// instance.encode(&mut serialized);
54///
55/// assert_eq!(vec![Felt::THREE, Felt::ZERO, Felt::ONE], serialized);
56/// ```
57pub trait Encode {
58    /// Converts the type into a list of [`Felt`] and append them into the writer.
59    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error>;
60}
61
62/// Any type that can be deserialized from a series of [Felt]s. This trait corresponds to the
63/// `deserialize` function of the Cairo `Serde` trait.
64///
65/// This trait can be derived as long as all the fields in type implement [`Encode`].
66///
67/// # Example
68///
69/// This example demonstrates deriving the trait and then using it to deserialize an instance from
70/// [`Vec<Felt>`].
71///
72/// ```rust
73/// use starknet_core::codec::Decode;
74/// # use starknet_core::types::Felt;
75///
76/// #[derive(Debug, PartialEq, Eq, Decode)]
77/// # #[starknet(core = "starknet_core")]
78/// struct CairoType {
79///     a: u32,
80///     b: Option<bool>,
81/// }
82///
83/// assert_eq!(
84///     CairoType {
85///         a: 3,
86///         b: Some(true)
87///     },
88///     CairoType::decode(&[Felt::THREE, Felt::ZERO, Felt::ONE]).unwrap()
89/// );
90/// ```
91pub trait Decode<'a>: Sized {
92    /// Converts into the type from a list of [`Felt`].
93    fn decode<T>(reader: T) -> Result<Self, Error>
94    where
95        T: IntoIterator<Item = &'a Felt>,
96    {
97        Self::decode_iter(&mut reader.into_iter())
98    }
99
100    /// Converts into the type from an iterator of references to [`Felt`].
101    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
102    where
103        T: Iterator<Item = &'a Felt>;
104}
105
106/// Error type for any encoding/decoding operations.
107///
108/// A simple string representation is forced onto all implementations for simplicity. This is
109/// because most of the time, a encoding/decoding error indicates a bug that requires human
110/// attention to fix anyway; even when handling untrusted data, the program is likely to only be
111/// interested in knowing that an error _did_ occur, instead of handling based on cause.
112///
113/// There might be cases where allocations must be avoided. A feature could be added in the future
114/// that turns the `repr` into `()` to address this. Such a feature would be a non-breaking change
115/// so there's no need to add it now.
116#[derive(Debug)]
117pub struct Error {
118    repr: Box<str>,
119}
120
121// This implementation is useful for encoding single-felt types.
122impl FeltWriter for Felt {
123    fn write(&mut self, felt: Felt) {
124        *self = felt;
125    }
126}
127
128impl FeltWriter for Vec<Felt> {
129    fn write(&mut self, felt: Felt) {
130        self.push(felt);
131    }
132}
133
134impl FeltWriter for PedersenHasher {
135    fn write(&mut self, felt: Felt) {
136        self.update(felt);
137    }
138}
139
140impl FeltWriter for PoseidonHasher {
141    fn write(&mut self, felt: Felt) {
142        self.update(felt);
143    }
144}
145
146impl Encode for Felt {
147    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
148        writer.write(*self);
149        Ok(())
150    }
151}
152
153impl Encode for bool {
154    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
155        writer.write(if *self { Felt::ONE } else { Felt::ZERO });
156        Ok(())
157    }
158}
159
160impl Encode for u8 {
161    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
162        writer.write((*self).into());
163        Ok(())
164    }
165}
166
167impl Encode for u16 {
168    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
169        writer.write((*self).into());
170        Ok(())
171    }
172}
173
174impl Encode for u32 {
175    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
176        writer.write((*self).into());
177        Ok(())
178    }
179}
180
181impl Encode for u64 {
182    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
183        writer.write((*self).into());
184        Ok(())
185    }
186}
187
188impl Encode for u128 {
189    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
190        writer.write((*self).into());
191        Ok(())
192    }
193}
194
195impl Encode for U256 {
196    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
197        self.low().encode(writer)?;
198        self.high().encode(writer)?;
199        Ok(())
200    }
201}
202
203impl Encode for i128 {
204    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
205        writer.write((*self).into());
206        Ok(())
207    }
208}
209
210impl<T> Encode for Option<T>
211where
212    T: Encode,
213{
214    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
215        match self {
216            Some(inner) => {
217                writer.write(Felt::ZERO);
218                inner.encode(writer)?;
219            }
220            None => {
221                writer.write(Felt::ONE);
222            }
223        }
224
225        Ok(())
226    }
227}
228
229impl<T> Encode for Vec<T>
230where
231    T: Encode,
232{
233    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
234        writer.write(Felt::from(self.len()));
235
236        for item in self {
237            item.encode(writer)?;
238        }
239
240        Ok(())
241    }
242}
243
244impl<T, const N: usize> Encode for [T; N]
245where
246    T: Encode,
247{
248    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
249        writer.write(Felt::from(N));
250
251        for item in self {
252            item.encode(writer)?;
253        }
254
255        Ok(())
256    }
257}
258
259impl<T> Encode for [T]
260where
261    T: Encode,
262{
263    fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
264        writer.write(Felt::from(self.len()));
265
266        for item in self {
267            item.encode(writer)?;
268        }
269
270        Ok(())
271    }
272}
273
274impl<'a> Decode<'a> for Felt {
275    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
276    where
277        T: Iterator<Item = &'a Self>,
278    {
279        iter.next().ok_or_else(Error::input_exhausted).cloned()
280    }
281}
282
283impl<'a> Decode<'a> for bool {
284    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
285    where
286        T: Iterator<Item = &'a Felt>,
287    {
288        let input = iter.next().ok_or_else(Error::input_exhausted)?;
289        if input == &Felt::ZERO {
290            Ok(false)
291        } else if input == &Felt::ONE {
292            Ok(true)
293        } else {
294            Err(Error::value_out_of_range(input, "bool"))
295        }
296    }
297}
298
299impl<'a> Decode<'a> for u8 {
300    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
301    where
302        T: Iterator<Item = &'a Felt>,
303    {
304        let input = iter.next().ok_or_else(Error::input_exhausted)?;
305        input
306            .to_u8()
307            .ok_or_else(|| Error::value_out_of_range(input, "u8"))
308    }
309}
310
311impl<'a> Decode<'a> for u16 {
312    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
313    where
314        T: Iterator<Item = &'a Felt>,
315    {
316        let input = iter.next().ok_or_else(Error::input_exhausted)?;
317        input
318            .to_u16()
319            .ok_or_else(|| Error::value_out_of_range(input, "u16"))
320    }
321}
322
323impl<'a> Decode<'a> for u32 {
324    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
325    where
326        T: Iterator<Item = &'a Felt>,
327    {
328        let input = iter.next().ok_or_else(Error::input_exhausted)?;
329        input
330            .to_u32()
331            .ok_or_else(|| Error::value_out_of_range(input, "u32"))
332    }
333}
334
335impl<'a> Decode<'a> for u64 {
336    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
337    where
338        T: Iterator<Item = &'a Felt>,
339    {
340        let input = iter.into_iter().next().ok_or_else(Error::input_exhausted)?;
341        input
342            .to_u64()
343            .ok_or_else(|| Error::value_out_of_range(input, "u64"))
344    }
345}
346
347impl<'a> Decode<'a> for u128 {
348    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
349    where
350        T: Iterator<Item = &'a Felt>,
351    {
352        let input = iter.next().ok_or_else(Error::input_exhausted)?;
353        input
354            .to_u128()
355            .ok_or_else(|| Error::value_out_of_range(input, "u128"))
356    }
357}
358
359impl<'a> Decode<'a> for U256 {
360    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
361    where
362        T: Iterator<Item = &'a Felt>,
363    {
364        let input_low = iter.next().ok_or_else(Error::input_exhausted)?;
365        let input_high = iter.next().ok_or_else(Error::input_exhausted)?;
366
367        let input_low = input_low
368            .to_u128()
369            .ok_or_else(|| Error::value_out_of_range(input_low, "u128"))?;
370        let input_high = input_high
371            .to_u128()
372            .ok_or_else(|| Error::value_out_of_range(input_high, "u128"))?;
373
374        Ok(Self::from_words(input_low, input_high))
375    }
376}
377
378impl<'a> Decode<'a> for i128 {
379    fn decode_iter<T>(iter: &mut T) -> Result<Self, Error>
380    where
381        T: Iterator<Item = &'a Felt>,
382    {
383        let input = iter.next().ok_or_else(Error::input_exhausted)?;
384
385        if input <= &I128_MAX {
386            // Range checked. Safe to unwrap.
387            Ok(input.to_i128().unwrap())
388        } else if input >= &I128_MIN {
389            // Range checked. Safe to unwrap.
390            Ok(Self::MIN + (input - I128_MIN).to_i128().unwrap())
391        } else {
392            Err(Error::value_out_of_range(input, "i128"))
393        }
394    }
395}
396
397impl<'a, T> Decode<'a> for Option<T>
398where
399    T: Decode<'a>,
400{
401    fn decode_iter<I>(iter: &mut I) -> Result<Self, Error>
402    where
403        I: Iterator<Item = &'a Felt>,
404    {
405        let tag = iter.next().ok_or_else(Error::input_exhausted)?;
406
407        if tag == &Felt::ZERO {
408            Ok(Some(T::decode_iter(iter)?))
409        } else if tag == &Felt::ONE {
410            Ok(None)
411        } else {
412            Err(Error::unknown_enum_tag(tag, "Option<T>"))
413        }
414    }
415}
416
417impl<'a, T> Decode<'a> for Vec<T>
418where
419    T: Decode<'a>,
420{
421    fn decode_iter<I>(iter: &mut I) -> Result<Self, Error>
422    where
423        I: Iterator<Item = &'a Felt>,
424    {
425        let length = iter.next().ok_or_else(Error::input_exhausted)?;
426        let length = length
427            .to_usize()
428            .ok_or_else(|| Error::value_out_of_range(length, "usize"))?;
429
430        let mut result = Self::with_capacity(length);
431
432        for _ in 0..length {
433            result.push(T::decode_iter(iter)?);
434        }
435
436        Ok(result)
437    }
438}
439
440impl<'a, T, const N: usize> Decode<'a> for [T; N]
441where
442    T: Decode<'a> + Sized,
443{
444    fn decode_iter<I>(iter: &mut I) -> Result<Self, Error>
445    where
446        I: Iterator<Item = &'a Felt>,
447    {
448        let length = iter.next().ok_or_else(Error::input_exhausted)?;
449        let length = length
450            .to_usize()
451            .ok_or_else(|| Error::value_out_of_range(length, "usize"))?;
452
453        if length != N {
454            return Err(Error::length_mismatch(N, length));
455        }
456
457        let mut result: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
458
459        for elem in &mut result[..] {
460            *elem = MaybeUninit::new(T::decode_iter(iter)?);
461        }
462
463        Ok(unsafe { core::mem::transmute_copy::<_, [T; N]>(&result) })
464    }
465}
466
467impl Error {
468    /// Creates an [`Error`] which indicates that the input stream has ended prematurely.
469    pub fn input_exhausted() -> Self {
470        Self {
471            repr: "unexpected end of input stream"
472                .to_string()
473                .into_boxed_str(),
474        }
475    }
476
477    /// Creates an [`Error`] which indicates that the length (likely prefix) is different from the
478    /// expected value.
479    pub fn length_mismatch(expected: usize, actual: usize) -> Self {
480        Self {
481            repr: format!("expecting length `{}` but got `{}`", expected, actual).into_boxed_str(),
482        }
483    }
484
485    /// Creates an [`Error`] which indicates that the input value is out of range.
486    pub fn value_out_of_range<V>(value: V, type_name: &str) -> Self
487    where
488        V: Display,
489    {
490        Self {
491            repr: format!("value `{}` is out of range for type `{}`", value, type_name)
492                .into_boxed_str(),
493        }
494    }
495
496    /// Creates an [`Error`] which indicates that the enum tag does not belong to a known variant.
497    pub fn unknown_enum_tag<V>(tag: V, type_name: &str) -> Self
498    where
499        V: Display,
500    {
501        Self {
502            repr: format!("enum tag `{}` is unknown for type `{}`", tag, type_name)
503                .into_boxed_str(),
504        }
505    }
506
507    /// Creates an [`Error`] using a custom error string.
508    pub fn custom<T>(content: T) -> Self
509    where
510        T: Display,
511    {
512        Self {
513            repr: content.to_string().into_boxed_str(),
514        }
515    }
516}
517
518#[cfg(feature = "std")]
519impl std::error::Error for Error {}
520
521impl Display for Error {
522    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
523        write!(f, "{}", self.repr)
524    }
525}
526
527#[cfg(test)]
528mod tests {
529    use core::str::FromStr;
530
531    use super::*;
532
533    #[test]
534    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
535    fn test_encode_felt() {
536        let mut serialized = Vec::<Felt>::new();
537        Felt::from_str("99999999999999999999999999")
538            .unwrap()
539            .encode(&mut serialized)
540            .unwrap();
541        assert_eq!(
542            serialized,
543            vec![Felt::from_str("99999999999999999999999999").unwrap()]
544        );
545    }
546
547    #[test]
548    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
549    fn test_encode_bool() {
550        let mut serialized = Vec::<Felt>::new();
551        true.encode(&mut serialized).unwrap();
552        assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]);
553
554        let mut serialized = Vec::<Felt>::new();
555        false.encode(&mut serialized).unwrap();
556        assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]);
557    }
558
559    #[test]
560    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
561    fn test_encode_u8() {
562        let mut serialized = Vec::<Felt>::new();
563        123u8.encode(&mut serialized).unwrap();
564        assert_eq!(serialized, vec![Felt::from_str("123").unwrap()]);
565    }
566
567    #[test]
568    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
569    fn test_encode_u16() {
570        let mut serialized = Vec::<Felt>::new();
571        12345u16.encode(&mut serialized).unwrap();
572        assert_eq!(serialized, vec![Felt::from_str("12345").unwrap()]);
573    }
574
575    #[test]
576    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
577    fn test_encode_u32() {
578        let mut serialized = Vec::<Felt>::new();
579        1234567890u32.encode(&mut serialized).unwrap();
580        assert_eq!(serialized, vec![Felt::from_str("1234567890").unwrap()]);
581    }
582
583    #[test]
584    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
585    fn test_encode_u64() {
586        let mut serialized = Vec::<Felt>::new();
587        12345678900000000000u64.encode(&mut serialized).unwrap();
588        assert_eq!(
589            serialized,
590            vec![Felt::from_str("12345678900000000000").unwrap()]
591        );
592    }
593
594    #[test]
595    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
596    fn test_encode_u128() {
597        let mut serialized = Vec::<Felt>::new();
598        123456789000000000000000000000u128
599            .encode(&mut serialized)
600            .unwrap();
601        assert_eq!(
602            serialized,
603            vec![Felt::from_str("123456789000000000000000000000").unwrap()]
604        );
605    }
606
607    #[test]
608    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
609    fn test_encode_i128() {
610        for (raw, felt) in [
611            (
612                0i128,
613                Felt::from_hex_unchecked(
614                    "0x0000000000000000000000000000000000000000000000000000000000000000",
615                ),
616            ),
617            (
618                -1i128,
619                Felt::from_hex_unchecked(
620                    "0x0800000000000011000000000000000000000000000000000000000000000000",
621                ),
622            ),
623            (
624                1i128,
625                Felt::from_hex_unchecked(
626                    "0x0000000000000000000000000000000000000000000000000000000000000001",
627                ),
628            ),
629            (
630                10000i128,
631                Felt::from_hex_unchecked(
632                    "0x0000000000000000000000000000000000000000000000000000000000002710",
633                ),
634            ),
635            (
636                -10000i128,
637                Felt::from_hex_unchecked(
638                    "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1",
639                ),
640            ),
641            (
642                i128::MIN,
643                Felt::from_hex_unchecked(
644                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000001",
645                ),
646            ),
647            (
648                i128::MIN + 1,
649                Felt::from_hex_unchecked(
650                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000002",
651                ),
652            ),
653            (
654                i128::MAX,
655                Felt::from_hex_unchecked(
656                    "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff",
657                ),
658            ),
659            (
660                i128::MAX - 1,
661                Felt::from_hex_unchecked(
662                    "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe",
663                ),
664            ),
665        ] {
666            let mut serialized = Vec::<Felt>::new();
667            raw.encode(&mut serialized).unwrap();
668            assert_eq!(serialized, vec![felt]);
669        }
670    }
671
672    #[test]
673    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
674    fn test_encode_u256() {
675        let mut serialized = Vec::<Felt>::new();
676        U256::from_words(12345, 67890)
677            .encode(&mut serialized)
678            .unwrap();
679        assert_eq!(
680            serialized,
681            vec![
682                Felt::from_str("12345").unwrap(),
683                Felt::from_str("67890").unwrap()
684            ]
685        );
686    }
687
688    #[test]
689    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
690    fn test_encode_option() {
691        let mut serialized = Vec::<Felt>::new();
692        Some(10u32).encode(&mut serialized).unwrap();
693        assert_eq!(
694            serialized,
695            vec![Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()]
696        );
697
698        serialized.clear();
699        Option::<u32>::None.encode(&mut serialized).unwrap();
700        assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]);
701    }
702
703    #[test]
704    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
705    fn test_encode_vec() {
706        let mut serialized = Vec::<Felt>::new();
707        vec![Some(10u32), None].encode(&mut serialized).unwrap();
708        assert_eq!(
709            serialized,
710            vec![
711                Felt::from_str("2").unwrap(),
712                Felt::from_str("0").unwrap(),
713                Felt::from_str("10").unwrap(),
714                Felt::from_str("1").unwrap()
715            ]
716        );
717    }
718
719    #[test]
720    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
721    fn test_encode_array() {
722        let mut serialized = Vec::<Felt>::new();
723        <[Option<u32>; 2]>::encode(&[Some(10u32), None], &mut serialized).unwrap();
724        assert_eq!(
725            serialized,
726            vec![
727                Felt::from_str("2").unwrap(),
728                Felt::from_str("0").unwrap(),
729                Felt::from_str("10").unwrap(),
730                Felt::from_str("1").unwrap()
731            ]
732        );
733    }
734
735    #[test]
736    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
737    fn test_encode_slice() {
738        let mut serialized = Vec::<Felt>::new();
739        <[Option<u32>]>::encode(&[Some(10u32), None], &mut serialized).unwrap();
740        assert_eq!(
741            serialized,
742            vec![
743                Felt::from_str("2").unwrap(),
744                Felt::from_str("0").unwrap(),
745                Felt::from_str("10").unwrap(),
746                Felt::from_str("1").unwrap()
747            ]
748        );
749    }
750
751    #[test]
752    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
753    fn test_derive_encode_struct_named() {
754        #[derive(Encode)]
755        #[starknet(core = "crate")]
756        struct CairoType {
757            a: Felt,
758            b: U256,
759            c: bool,
760        }
761
762        let mut serialized = Vec::<Felt>::new();
763        CairoType {
764            a: Felt::from_str("12345").unwrap(),
765            b: U256::from_words(12, 34),
766            c: true,
767        }
768        .encode(&mut serialized)
769        .unwrap();
770        assert_eq!(
771            serialized,
772            vec![
773                Felt::from_str("12345").unwrap(),
774                Felt::from_str("12").unwrap(),
775                Felt::from_str("34").unwrap(),
776                Felt::from_str("1").unwrap(),
777            ]
778        );
779    }
780
781    #[test]
782    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
783    fn test_derive_encode_struct_tuple() {
784        #[derive(Encode)]
785        #[starknet(core = "crate")]
786        struct CairoType(Felt, U256, bool);
787
788        let mut serialized = Vec::<Felt>::new();
789        CairoType(
790            Felt::from_str("12345").unwrap(),
791            U256::from_words(12, 34),
792            true,
793        )
794        .encode(&mut serialized)
795        .unwrap();
796        assert_eq!(
797            serialized,
798            vec![
799                Felt::from_str("12345").unwrap(),
800                Felt::from_str("12").unwrap(),
801                Felt::from_str("34").unwrap(),
802                Felt::from_str("1").unwrap(),
803            ]
804        );
805    }
806
807    #[test]
808    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
809    fn test_derive_encode_enum() {
810        #[derive(Encode)]
811        #[starknet(core = "crate")]
812        enum CairoType {
813            A,
814            B(bool),
815            C(Option<U256>, u8),
816            D { a: u64, b: bool },
817        }
818
819        let mut serialized = Vec::<Felt>::new();
820        CairoType::A.encode(&mut serialized).unwrap();
821        assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]);
822
823        serialized.clear();
824        CairoType::B(true).encode(&mut serialized).unwrap();
825        assert_eq!(
826            serialized,
827            vec![Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()]
828        );
829
830        serialized.clear();
831        CairoType::C(Some(U256::from_words(12, 23)), 4)
832            .encode(&mut serialized)
833            .unwrap();
834        assert_eq!(
835            serialized,
836            vec![
837                Felt::from_str("2").unwrap(),
838                Felt::from_str("0").unwrap(),
839                Felt::from_str("12").unwrap(),
840                Felt::from_str("23").unwrap(),
841                Felt::from_str("4").unwrap(),
842            ]
843        );
844
845        serialized.clear();
846        CairoType::C(None, 8).encode(&mut serialized).unwrap();
847        assert_eq!(
848            serialized,
849            vec![
850                Felt::from_str("2").unwrap(),
851                Felt::from_str("1").unwrap(),
852                Felt::from_str("8").unwrap(),
853            ]
854        );
855
856        serialized.clear();
857        CairoType::D { a: 100, b: false }
858            .encode(&mut serialized)
859            .unwrap();
860        assert_eq!(
861            serialized,
862            vec![
863                Felt::from_str("3").unwrap(),
864                Felt::from_str("100").unwrap(),
865                Felt::from_str("0").unwrap()
866            ]
867        );
868    }
869
870    #[test]
871    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
872    fn test_decode_felt() {
873        assert_eq!(
874            Felt::from_str("99999999999999999999999999").unwrap(),
875            Felt::decode(&[Felt::from_str("99999999999999999999999999").unwrap()]).unwrap()
876        );
877    }
878
879    #[allow(clippy::bool_assert_comparison)]
880    #[test]
881    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
882    fn test_decode_bool() {
883        assert_eq!(true, bool::decode(&[Felt::from_str("1").unwrap()]).unwrap());
884
885        assert_eq!(
886            false,
887            bool::decode(&[Felt::from_str("0").unwrap()]).unwrap()
888        );
889    }
890
891    #[test]
892    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
893    fn test_decode_u8() {
894        assert_eq!(
895            123u8,
896            u8::decode(&[Felt::from_str("123").unwrap()]).unwrap()
897        );
898    }
899
900    #[test]
901    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
902    fn test_decode_u16() {
903        assert_eq!(
904            12345u16,
905            u16::decode(&[Felt::from_str("12345").unwrap()]).unwrap()
906        );
907    }
908
909    #[test]
910    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
911    fn test_decode_u32() {
912        assert_eq!(
913            1234567890u32,
914            u32::decode(&[Felt::from_str("1234567890").unwrap()]).unwrap()
915        );
916    }
917
918    #[test]
919    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
920    fn test_decode_u64() {
921        assert_eq!(
922            12345678900000000000u64,
923            u64::decode(&[Felt::from_str("12345678900000000000").unwrap()]).unwrap()
924        );
925    }
926
927    #[test]
928    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
929    fn test_decode_u128() {
930        assert_eq!(
931            123456789000000000000000000000u128,
932            u128::decode(&[Felt::from_str("123456789000000000000000000000").unwrap()]).unwrap()
933        );
934    }
935
936    #[test]
937    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
938    fn test_decode_i128() {
939        for (raw, felt) in [
940            (
941                0i128,
942                Felt::from_hex_unchecked(
943                    "0x0000000000000000000000000000000000000000000000000000000000000000",
944                ),
945            ),
946            (
947                -1i128,
948                Felt::from_hex_unchecked(
949                    "0x0800000000000011000000000000000000000000000000000000000000000000",
950                ),
951            ),
952            (
953                1i128,
954                Felt::from_hex_unchecked(
955                    "0x0000000000000000000000000000000000000000000000000000000000000001",
956                ),
957            ),
958            (
959                10000i128,
960                Felt::from_hex_unchecked(
961                    "0x0000000000000000000000000000000000000000000000000000000000002710",
962                ),
963            ),
964            (
965                -10000i128,
966                Felt::from_hex_unchecked(
967                    "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1",
968                ),
969            ),
970            (
971                i128::MIN,
972                Felt::from_hex_unchecked(
973                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000001",
974                ),
975            ),
976            (
977                i128::MIN + 1,
978                Felt::from_hex_unchecked(
979                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000002",
980                ),
981            ),
982            (
983                i128::MAX,
984                Felt::from_hex_unchecked(
985                    "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff",
986                ),
987            ),
988            (
989                i128::MAX - 1,
990                Felt::from_hex_unchecked(
991                    "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe",
992                ),
993            ),
994        ] {
995            assert_eq!(raw, i128::decode(&[felt]).unwrap());
996        }
997    }
998
999    #[test]
1000    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1001    fn test_decode_u256() {
1002        assert_eq!(
1003            U256::from_words(12345, 67890),
1004            U256::decode(&[
1005                Felt::from_str("12345").unwrap(),
1006                Felt::from_str("67890").unwrap()
1007            ])
1008            .unwrap()
1009        );
1010    }
1011
1012    #[test]
1013    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1014    fn test_decode_option() {
1015        assert_eq!(
1016            Some(10u32),
1017            Option::<u32>::decode(&[Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()])
1018                .unwrap()
1019        );
1020
1021        assert_eq!(
1022            Option::<u32>::None,
1023            Option::<u32>::decode(&[Felt::from_str("1").unwrap()]).unwrap()
1024        );
1025    }
1026
1027    #[test]
1028    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1029    fn test_decode_vec() {
1030        assert_eq!(
1031            vec![Some(10u32), None],
1032            Vec::<Option::<u32>>::decode(&[
1033                Felt::from_str("2").unwrap(),
1034                Felt::from_str("0").unwrap(),
1035                Felt::from_str("10").unwrap(),
1036                Felt::from_str("1").unwrap()
1037            ])
1038            .unwrap()
1039        );
1040    }
1041
1042    #[test]
1043    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1044    fn test_decode_array() {
1045        assert_eq!(
1046            [Some(10u32), None],
1047            <[Option<u32>; 2]>::decode(&[
1048                Felt::from_str("2").unwrap(),
1049                Felt::from_str("0").unwrap(),
1050                Felt::from_str("10").unwrap(),
1051                Felt::from_str("1").unwrap()
1052            ])
1053            .unwrap()
1054        );
1055    }
1056
1057    #[test]
1058    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1059    fn test_derive_decode_struct_named() {
1060        #[derive(Debug, PartialEq, Eq, Decode)]
1061        #[starknet(core = "crate")]
1062        struct CairoType {
1063            a: Felt,
1064            b: U256,
1065            c: bool,
1066        }
1067
1068        assert_eq!(
1069            CairoType {
1070                a: Felt::from_str("12345").unwrap(),
1071                b: U256::from_words(12, 34),
1072                c: true,
1073            },
1074            CairoType::decode(&[
1075                Felt::from_str("12345").unwrap(),
1076                Felt::from_str("12").unwrap(),
1077                Felt::from_str("34").unwrap(),
1078                Felt::from_str("1").unwrap(),
1079            ])
1080            .unwrap()
1081        );
1082    }
1083
1084    #[test]
1085    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1086    fn test_derive_decode_struct_tuple() {
1087        #[derive(Debug, PartialEq, Eq, Decode)]
1088        #[starknet(core = "crate")]
1089        struct CairoType(Felt, U256, bool);
1090
1091        assert_eq!(
1092            CairoType(
1093                Felt::from_str("12345").unwrap(),
1094                U256::from_words(12, 34),
1095                true,
1096            ),
1097            CairoType::decode(&[
1098                Felt::from_str("12345").unwrap(),
1099                Felt::from_str("12").unwrap(),
1100                Felt::from_str("34").unwrap(),
1101                Felt::from_str("1").unwrap(),
1102            ])
1103            .unwrap()
1104        );
1105    }
1106
1107    #[test]
1108    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1109    fn test_derive_decode_enum() {
1110        #[derive(Debug, PartialEq, Eq, Decode)]
1111        #[starknet(core = "crate")]
1112        enum CairoType {
1113            A,
1114            B(bool),
1115            C(Option<U256>, u8),
1116            D { a: u64, b: bool },
1117        }
1118
1119        assert_eq!(
1120            CairoType::A,
1121            CairoType::decode(&[Felt::from_str("0").unwrap()]).unwrap()
1122        );
1123
1124        assert_eq!(
1125            CairoType::B(true),
1126            CairoType::decode(&[Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()])
1127                .unwrap()
1128        );
1129
1130        assert_eq!(
1131            CairoType::C(Some(U256::from_words(12, 23)), 4),
1132            CairoType::decode(&[
1133                Felt::from_str("2").unwrap(),
1134                Felt::from_str("0").unwrap(),
1135                Felt::from_str("12").unwrap(),
1136                Felt::from_str("23").unwrap(),
1137                Felt::from_str("4").unwrap(),
1138            ])
1139            .unwrap()
1140        );
1141
1142        assert_eq!(
1143            CairoType::C(None, 8),
1144            CairoType::decode(&[
1145                Felt::from_str("2").unwrap(),
1146                Felt::from_str("1").unwrap(),
1147                Felt::from_str("8").unwrap(),
1148            ])
1149            .unwrap()
1150        );
1151
1152        assert_eq!(
1153            CairoType::D { a: 100, b: false },
1154            CairoType::decode(&[
1155                Felt::from_str("3").unwrap(),
1156                Felt::from_str("100").unwrap(),
1157                Felt::from_str("0").unwrap()
1158            ])
1159            .unwrap()
1160        );
1161    }
1162}