starknet_rust_core/
codec.rs

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