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 `{expected}` but got `{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 `{value}` is out of range for type `{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 `{tag}` is unknown for type `{type_name}`").into_boxed_str(),
503        }
504    }
505
506    /// Creates an [`Error`] using a custom error string.
507    pub fn custom<T>(content: T) -> Self
508    where
509        T: Display,
510    {
511        Self {
512            repr: content.to_string().into_boxed_str(),
513        }
514    }
515}
516
517#[cfg(feature = "std")]
518impl std::error::Error for Error {}
519
520impl Display for Error {
521    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
522        write!(f, "{}", self.repr)
523    }
524}
525
526#[cfg(test)]
527mod tests {
528    use core::str::FromStr;
529
530    use super::*;
531
532    #[test]
533    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
534    fn test_encode_felt() {
535        let mut serialized = Vec::<Felt>::new();
536        Felt::from_str("99999999999999999999999999")
537            .unwrap()
538            .encode(&mut serialized)
539            .unwrap();
540        assert_eq!(
541            serialized,
542            vec![Felt::from_str("99999999999999999999999999").unwrap()]
543        );
544    }
545
546    #[test]
547    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
548    fn test_encode_bool() {
549        let mut serialized = Vec::<Felt>::new();
550        true.encode(&mut serialized).unwrap();
551        assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]);
552
553        let mut serialized = Vec::<Felt>::new();
554        false.encode(&mut serialized).unwrap();
555        assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]);
556    }
557
558    #[test]
559    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
560    fn test_encode_u8() {
561        let mut serialized = Vec::<Felt>::new();
562        123u8.encode(&mut serialized).unwrap();
563        assert_eq!(serialized, vec![Felt::from_str("123").unwrap()]);
564    }
565
566    #[test]
567    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
568    fn test_encode_u16() {
569        let mut serialized = Vec::<Felt>::new();
570        12345u16.encode(&mut serialized).unwrap();
571        assert_eq!(serialized, vec![Felt::from_str("12345").unwrap()]);
572    }
573
574    #[test]
575    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
576    fn test_encode_u32() {
577        let mut serialized = Vec::<Felt>::new();
578        1234567890u32.encode(&mut serialized).unwrap();
579        assert_eq!(serialized, vec![Felt::from_str("1234567890").unwrap()]);
580    }
581
582    #[test]
583    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
584    fn test_encode_u64() {
585        let mut serialized = Vec::<Felt>::new();
586        12345678900000000000u64.encode(&mut serialized).unwrap();
587        assert_eq!(
588            serialized,
589            vec![Felt::from_str("12345678900000000000").unwrap()]
590        );
591    }
592
593    #[test]
594    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
595    fn test_encode_u128() {
596        let mut serialized = Vec::<Felt>::new();
597        123456789000000000000000000000u128
598            .encode(&mut serialized)
599            .unwrap();
600        assert_eq!(
601            serialized,
602            vec![Felt::from_str("123456789000000000000000000000").unwrap()]
603        );
604    }
605
606    #[test]
607    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
608    fn test_encode_i128() {
609        for (raw, felt) in [
610            (
611                0i128,
612                Felt::from_hex_unchecked(
613                    "0x0000000000000000000000000000000000000000000000000000000000000000",
614                ),
615            ),
616            (
617                -1i128,
618                Felt::from_hex_unchecked(
619                    "0x0800000000000011000000000000000000000000000000000000000000000000",
620                ),
621            ),
622            (
623                1i128,
624                Felt::from_hex_unchecked(
625                    "0x0000000000000000000000000000000000000000000000000000000000000001",
626                ),
627            ),
628            (
629                10000i128,
630                Felt::from_hex_unchecked(
631                    "0x0000000000000000000000000000000000000000000000000000000000002710",
632                ),
633            ),
634            (
635                -10000i128,
636                Felt::from_hex_unchecked(
637                    "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1",
638                ),
639            ),
640            (
641                i128::MIN,
642                Felt::from_hex_unchecked(
643                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000001",
644                ),
645            ),
646            (
647                i128::MIN + 1,
648                Felt::from_hex_unchecked(
649                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000002",
650                ),
651            ),
652            (
653                i128::MAX,
654                Felt::from_hex_unchecked(
655                    "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff",
656                ),
657            ),
658            (
659                i128::MAX - 1,
660                Felt::from_hex_unchecked(
661                    "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe",
662                ),
663            ),
664        ] {
665            let mut serialized = Vec::<Felt>::new();
666            raw.encode(&mut serialized).unwrap();
667            assert_eq!(serialized, vec![felt]);
668        }
669    }
670
671    #[test]
672    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
673    fn test_encode_u256() {
674        let mut serialized = Vec::<Felt>::new();
675        U256::from_words(12345, 67890)
676            .encode(&mut serialized)
677            .unwrap();
678        assert_eq!(
679            serialized,
680            vec![
681                Felt::from_str("12345").unwrap(),
682                Felt::from_str("67890").unwrap()
683            ]
684        );
685    }
686
687    #[test]
688    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
689    fn test_encode_option() {
690        let mut serialized = Vec::<Felt>::new();
691        Some(10u32).encode(&mut serialized).unwrap();
692        assert_eq!(
693            serialized,
694            vec![Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()]
695        );
696
697        serialized.clear();
698        Option::<u32>::None.encode(&mut serialized).unwrap();
699        assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]);
700    }
701
702    #[test]
703    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
704    fn test_encode_vec() {
705        let mut serialized = Vec::<Felt>::new();
706        vec![Some(10u32), None].encode(&mut serialized).unwrap();
707        assert_eq!(
708            serialized,
709            vec![
710                Felt::from_str("2").unwrap(),
711                Felt::from_str("0").unwrap(),
712                Felt::from_str("10").unwrap(),
713                Felt::from_str("1").unwrap()
714            ]
715        );
716    }
717
718    #[test]
719    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
720    fn test_encode_array() {
721        let mut serialized = Vec::<Felt>::new();
722        <[Option<u32>; 2]>::encode(&[Some(10u32), None], &mut serialized).unwrap();
723        assert_eq!(
724            serialized,
725            vec![
726                Felt::from_str("2").unwrap(),
727                Felt::from_str("0").unwrap(),
728                Felt::from_str("10").unwrap(),
729                Felt::from_str("1").unwrap()
730            ]
731        );
732    }
733
734    #[test]
735    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
736    fn test_encode_slice() {
737        let mut serialized = Vec::<Felt>::new();
738        <[Option<u32>]>::encode(&[Some(10u32), None], &mut serialized).unwrap();
739        assert_eq!(
740            serialized,
741            vec![
742                Felt::from_str("2").unwrap(),
743                Felt::from_str("0").unwrap(),
744                Felt::from_str("10").unwrap(),
745                Felt::from_str("1").unwrap()
746            ]
747        );
748    }
749
750    #[test]
751    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
752    fn test_derive_encode_struct_named() {
753        #[derive(Encode)]
754        #[starknet(core = "crate")]
755        struct CairoType {
756            a: Felt,
757            b: U256,
758            c: bool,
759        }
760
761        let mut serialized = Vec::<Felt>::new();
762        CairoType {
763            a: Felt::from_str("12345").unwrap(),
764            b: U256::from_words(12, 34),
765            c: true,
766        }
767        .encode(&mut serialized)
768        .unwrap();
769        assert_eq!(
770            serialized,
771            vec![
772                Felt::from_str("12345").unwrap(),
773                Felt::from_str("12").unwrap(),
774                Felt::from_str("34").unwrap(),
775                Felt::from_str("1").unwrap(),
776            ]
777        );
778    }
779
780    #[test]
781    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
782    fn test_derive_encode_struct_tuple() {
783        #[derive(Encode)]
784        #[starknet(core = "crate")]
785        struct CairoType(Felt, U256, bool);
786
787        let mut serialized = Vec::<Felt>::new();
788        CairoType(
789            Felt::from_str("12345").unwrap(),
790            U256::from_words(12, 34),
791            true,
792        )
793        .encode(&mut serialized)
794        .unwrap();
795        assert_eq!(
796            serialized,
797            vec![
798                Felt::from_str("12345").unwrap(),
799                Felt::from_str("12").unwrap(),
800                Felt::from_str("34").unwrap(),
801                Felt::from_str("1").unwrap(),
802            ]
803        );
804    }
805
806    #[test]
807    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
808    fn test_derive_encode_enum() {
809        #[derive(Encode)]
810        #[starknet(core = "crate")]
811        enum CairoType {
812            A,
813            B(bool),
814            C(Option<U256>, u8),
815            D { a: u64, b: bool },
816        }
817
818        let mut serialized = Vec::<Felt>::new();
819        CairoType::A.encode(&mut serialized).unwrap();
820        assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]);
821
822        serialized.clear();
823        CairoType::B(true).encode(&mut serialized).unwrap();
824        assert_eq!(
825            serialized,
826            vec![Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()]
827        );
828
829        serialized.clear();
830        CairoType::C(Some(U256::from_words(12, 23)), 4)
831            .encode(&mut serialized)
832            .unwrap();
833        assert_eq!(
834            serialized,
835            vec![
836                Felt::from_str("2").unwrap(),
837                Felt::from_str("0").unwrap(),
838                Felt::from_str("12").unwrap(),
839                Felt::from_str("23").unwrap(),
840                Felt::from_str("4").unwrap(),
841            ]
842        );
843
844        serialized.clear();
845        CairoType::C(None, 8).encode(&mut serialized).unwrap();
846        assert_eq!(
847            serialized,
848            vec![
849                Felt::from_str("2").unwrap(),
850                Felt::from_str("1").unwrap(),
851                Felt::from_str("8").unwrap(),
852            ]
853        );
854
855        serialized.clear();
856        CairoType::D { a: 100, b: false }
857            .encode(&mut serialized)
858            .unwrap();
859        assert_eq!(
860            serialized,
861            vec![
862                Felt::from_str("3").unwrap(),
863                Felt::from_str("100").unwrap(),
864                Felt::from_str("0").unwrap()
865            ]
866        );
867    }
868
869    #[test]
870    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
871    fn test_decode_felt() {
872        assert_eq!(
873            Felt::from_str("99999999999999999999999999").unwrap(),
874            Felt::decode(&[Felt::from_str("99999999999999999999999999").unwrap()]).unwrap()
875        );
876    }
877
878    #[allow(clippy::bool_assert_comparison)]
879    #[test]
880    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
881    fn test_decode_bool() {
882        assert_eq!(true, bool::decode(&[Felt::from_str("1").unwrap()]).unwrap());
883
884        assert_eq!(
885            false,
886            bool::decode(&[Felt::from_str("0").unwrap()]).unwrap()
887        );
888    }
889
890    #[test]
891    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
892    fn test_decode_u8() {
893        assert_eq!(
894            123u8,
895            u8::decode(&[Felt::from_str("123").unwrap()]).unwrap()
896        );
897    }
898
899    #[test]
900    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
901    fn test_decode_u16() {
902        assert_eq!(
903            12345u16,
904            u16::decode(&[Felt::from_str("12345").unwrap()]).unwrap()
905        );
906    }
907
908    #[test]
909    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
910    fn test_decode_u32() {
911        assert_eq!(
912            1234567890u32,
913            u32::decode(&[Felt::from_str("1234567890").unwrap()]).unwrap()
914        );
915    }
916
917    #[test]
918    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
919    fn test_decode_u64() {
920        assert_eq!(
921            12345678900000000000u64,
922            u64::decode(&[Felt::from_str("12345678900000000000").unwrap()]).unwrap()
923        );
924    }
925
926    #[test]
927    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
928    fn test_decode_u128() {
929        assert_eq!(
930            123456789000000000000000000000u128,
931            u128::decode(&[Felt::from_str("123456789000000000000000000000").unwrap()]).unwrap()
932        );
933    }
934
935    #[test]
936    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
937    fn test_decode_i128() {
938        for (raw, felt) in [
939            (
940                0i128,
941                Felt::from_hex_unchecked(
942                    "0x0000000000000000000000000000000000000000000000000000000000000000",
943                ),
944            ),
945            (
946                -1i128,
947                Felt::from_hex_unchecked(
948                    "0x0800000000000011000000000000000000000000000000000000000000000000",
949                ),
950            ),
951            (
952                1i128,
953                Felt::from_hex_unchecked(
954                    "0x0000000000000000000000000000000000000000000000000000000000000001",
955                ),
956            ),
957            (
958                10000i128,
959                Felt::from_hex_unchecked(
960                    "0x0000000000000000000000000000000000000000000000000000000000002710",
961                ),
962            ),
963            (
964                -10000i128,
965                Felt::from_hex_unchecked(
966                    "0x0800000000000010ffffffffffffffffffffffffffffffffffffffffffffd8f1",
967                ),
968            ),
969            (
970                i128::MIN,
971                Felt::from_hex_unchecked(
972                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000001",
973                ),
974            ),
975            (
976                i128::MIN + 1,
977                Felt::from_hex_unchecked(
978                    "0x0800000000000010ffffffffffffffff80000000000000000000000000000002",
979                ),
980            ),
981            (
982                i128::MAX,
983                Felt::from_hex_unchecked(
984                    "0x000000000000000000000000000000007fffffffffffffffffffffffffffffff",
985                ),
986            ),
987            (
988                i128::MAX - 1,
989                Felt::from_hex_unchecked(
990                    "0x000000000000000000000000000000007ffffffffffffffffffffffffffffffe",
991                ),
992            ),
993        ] {
994            assert_eq!(raw, i128::decode(&[felt]).unwrap());
995        }
996    }
997
998    #[test]
999    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1000    fn test_decode_u256() {
1001        assert_eq!(
1002            U256::from_words(12345, 67890),
1003            U256::decode(&[
1004                Felt::from_str("12345").unwrap(),
1005                Felt::from_str("67890").unwrap()
1006            ])
1007            .unwrap()
1008        );
1009    }
1010
1011    #[test]
1012    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1013    fn test_decode_option() {
1014        assert_eq!(
1015            Some(10u32),
1016            Option::<u32>::decode(&[Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()])
1017                .unwrap()
1018        );
1019
1020        assert_eq!(
1021            Option::<u32>::None,
1022            Option::<u32>::decode(&[Felt::from_str("1").unwrap()]).unwrap()
1023        );
1024    }
1025
1026    #[test]
1027    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1028    fn test_decode_vec() {
1029        assert_eq!(
1030            vec![Some(10u32), None],
1031            Vec::<Option::<u32>>::decode(&[
1032                Felt::from_str("2").unwrap(),
1033                Felt::from_str("0").unwrap(),
1034                Felt::from_str("10").unwrap(),
1035                Felt::from_str("1").unwrap()
1036            ])
1037            .unwrap()
1038        );
1039    }
1040
1041    #[test]
1042    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1043    fn test_decode_array() {
1044        assert_eq!(
1045            [Some(10u32), None],
1046            <[Option<u32>; 2]>::decode(&[
1047                Felt::from_str("2").unwrap(),
1048                Felt::from_str("0").unwrap(),
1049                Felt::from_str("10").unwrap(),
1050                Felt::from_str("1").unwrap()
1051            ])
1052            .unwrap()
1053        );
1054    }
1055
1056    #[test]
1057    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1058    fn test_derive_decode_struct_named() {
1059        #[derive(Debug, PartialEq, Eq, Decode)]
1060        #[starknet(core = "crate")]
1061        struct CairoType {
1062            a: Felt,
1063            b: U256,
1064            c: bool,
1065        }
1066
1067        assert_eq!(
1068            CairoType {
1069                a: Felt::from_str("12345").unwrap(),
1070                b: U256::from_words(12, 34),
1071                c: true,
1072            },
1073            CairoType::decode(&[
1074                Felt::from_str("12345").unwrap(),
1075                Felt::from_str("12").unwrap(),
1076                Felt::from_str("34").unwrap(),
1077                Felt::from_str("1").unwrap(),
1078            ])
1079            .unwrap()
1080        );
1081    }
1082
1083    #[test]
1084    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1085    fn test_derive_decode_struct_tuple() {
1086        #[derive(Debug, PartialEq, Eq, Decode)]
1087        #[starknet(core = "crate")]
1088        struct CairoType(Felt, U256, bool);
1089
1090        assert_eq!(
1091            CairoType(
1092                Felt::from_str("12345").unwrap(),
1093                U256::from_words(12, 34),
1094                true,
1095            ),
1096            CairoType::decode(&[
1097                Felt::from_str("12345").unwrap(),
1098                Felt::from_str("12").unwrap(),
1099                Felt::from_str("34").unwrap(),
1100                Felt::from_str("1").unwrap(),
1101            ])
1102            .unwrap()
1103        );
1104    }
1105
1106    #[test]
1107    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
1108    fn test_derive_decode_enum() {
1109        #[derive(Debug, PartialEq, Eq, Decode)]
1110        #[starknet(core = "crate")]
1111        enum CairoType {
1112            A,
1113            B(bool),
1114            C(Option<U256>, u8),
1115            D { a: u64, b: bool },
1116        }
1117
1118        assert_eq!(
1119            CairoType::A,
1120            CairoType::decode(&[Felt::from_str("0").unwrap()]).unwrap()
1121        );
1122
1123        assert_eq!(
1124            CairoType::B(true),
1125            CairoType::decode(&[Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()])
1126                .unwrap()
1127        );
1128
1129        assert_eq!(
1130            CairoType::C(Some(U256::from_words(12, 23)), 4),
1131            CairoType::decode(&[
1132                Felt::from_str("2").unwrap(),
1133                Felt::from_str("0").unwrap(),
1134                Felt::from_str("12").unwrap(),
1135                Felt::from_str("23").unwrap(),
1136                Felt::from_str("4").unwrap(),
1137            ])
1138            .unwrap()
1139        );
1140
1141        assert_eq!(
1142            CairoType::C(None, 8),
1143            CairoType::decode(&[
1144                Felt::from_str("2").unwrap(),
1145                Felt::from_str("1").unwrap(),
1146                Felt::from_str("8").unwrap(),
1147            ])
1148            .unwrap()
1149        );
1150
1151        assert_eq!(
1152            CairoType::D { a: 100, b: false },
1153            CairoType::decode(&[
1154                Felt::from_str("3").unwrap(),
1155                Felt::from_str("100").unwrap(),
1156                Felt::from_str("0").unwrap()
1157            ])
1158            .unwrap()
1159        );
1160    }
1161}