casper_types/
cl_type.rs

1use alloc::{
2    boxed::Box,
3    collections::{BTreeMap, BTreeSet, VecDeque},
4    string::String,
5    vec::Vec,
6};
7use core::fmt::{self, Display, Formatter};
8
9#[cfg(feature = "datasize")]
10use datasize::DataSize;
11use num_rational::Ratio;
12#[cfg(feature = "json-schema")]
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15
16use crate::{
17    bytesrepr::{self, FromBytes, ToBytes},
18    Key, URef, U128, U256, U512,
19};
20
21// This must be less than 300 in order to avoid a stack overflow when deserializing.
22pub(crate) const CL_TYPE_RECURSION_DEPTH: u8 = 50;
23
24const CL_TYPE_TAG_BOOL: u8 = 0;
25const CL_TYPE_TAG_I32: u8 = 1;
26const CL_TYPE_TAG_I64: u8 = 2;
27const CL_TYPE_TAG_U8: u8 = 3;
28const CL_TYPE_TAG_U32: u8 = 4;
29const CL_TYPE_TAG_U64: u8 = 5;
30const CL_TYPE_TAG_U128: u8 = 6;
31const CL_TYPE_TAG_U256: u8 = 7;
32const CL_TYPE_TAG_U512: u8 = 8;
33const CL_TYPE_TAG_UNIT: u8 = 9;
34const CL_TYPE_TAG_STRING: u8 = 10;
35const CL_TYPE_TAG_KEY: u8 = 11;
36const CL_TYPE_TAG_UREF: u8 = 12;
37const CL_TYPE_TAG_OPTION: u8 = 13;
38const CL_TYPE_TAG_LIST: u8 = 14;
39const CL_TYPE_TAG_BYTE_ARRAY: u8 = 15;
40const CL_TYPE_TAG_RESULT: u8 = 16;
41const CL_TYPE_TAG_MAP: u8 = 17;
42const CL_TYPE_TAG_TUPLE1: u8 = 18;
43const CL_TYPE_TAG_TUPLE2: u8 = 19;
44const CL_TYPE_TAG_TUPLE3: u8 = 20;
45const CL_TYPE_TAG_ANY: u8 = 21;
46const CL_TYPE_TAG_PUBLIC_KEY: u8 = 22;
47
48/// Casper types, i.e. types which can be stored and manipulated by smart contracts.
49///
50/// Provides a description of the underlying data type of a [`CLValue`](crate::CLValue).
51#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize, Debug)]
52#[cfg_attr(feature = "datasize", derive(DataSize))]
53#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
54#[serde(deny_unknown_fields)]
55pub enum CLType {
56    /// `bool` primitive.
57    Bool,
58    /// `i32` primitive.
59    I32,
60    /// `i64` primitive.
61    I64,
62    /// `u8` primitive.
63    U8,
64    /// `u32` primitive.
65    U32,
66    /// `u64` primitive.
67    U64,
68    /// [`U128`] large unsigned integer type.
69    U128,
70    /// [`U256`] large unsigned integer type.
71    U256,
72    /// [`U512`] large unsigned integer type.
73    U512,
74    /// `()` primitive.
75    Unit,
76    /// `String` primitive.
77    String,
78    /// [`Key`] system type.
79    Key,
80    /// [`URef`] system type.
81    URef,
82    /// [`PublicKey`](crate::PublicKey) system type.
83    PublicKey,
84    /// `Option` of a `CLType`.
85    #[cfg_attr(feature = "datasize", data_size(skip))]
86    Option(Box<CLType>),
87    /// Variable-length list of a single `CLType` (comparable to a `Vec`).
88    #[cfg_attr(feature = "datasize", data_size(skip))]
89    List(Box<CLType>),
90    /// Fixed-length list of a single `CLType` (comparable to a Rust array).
91    ByteArray(u32),
92    /// `Result` with `Ok` and `Err` variants of `CLType`s.
93    #[allow(missing_docs)] // generated docs are explicit enough.
94    #[cfg_attr(feature = "datasize", data_size(skip))]
95    Result { ok: Box<CLType>, err: Box<CLType> },
96    /// Map with keys of a single `CLType` and values of a single `CLType`.
97    #[allow(missing_docs)] // generated docs are explicit enough.
98    #[cfg_attr(feature = "datasize", data_size(skip))]
99    Map {
100        key: Box<CLType>,
101        value: Box<CLType>,
102    },
103    /// 1-ary tuple of a `CLType`.
104    #[cfg_attr(feature = "datasize", data_size(skip))]
105    Tuple1([Box<CLType>; 1]),
106    /// 2-ary tuple of `CLType`s.
107    #[cfg_attr(feature = "datasize", data_size(skip))]
108    Tuple2([Box<CLType>; 2]),
109    /// 3-ary tuple of `CLType`s.
110    #[cfg_attr(feature = "datasize", data_size(skip))]
111    Tuple3([Box<CLType>; 3]),
112    /// Unspecified type.
113    Any,
114}
115
116impl CLType {
117    /// The `len()` of the `Vec<u8>` resulting from `self.to_bytes()`.
118    pub fn serialized_length(&self) -> usize {
119        size_of::<u8>()
120            + match self {
121                CLType::Bool
122                | CLType::I32
123                | CLType::I64
124                | CLType::U8
125                | CLType::U32
126                | CLType::U64
127                | CLType::U128
128                | CLType::U256
129                | CLType::U512
130                | CLType::Unit
131                | CLType::String
132                | CLType::Key
133                | CLType::URef
134                | CLType::PublicKey
135                | CLType::Any => 0,
136                CLType::Option(cl_type) | CLType::List(cl_type) => cl_type.serialized_length(),
137                CLType::ByteArray(list_len) => list_len.serialized_length(),
138                CLType::Result { ok, err } => ok.serialized_length() + err.serialized_length(),
139                CLType::Map { key, value } => key.serialized_length() + value.serialized_length(),
140                CLType::Tuple1(cl_type_array) => serialized_length_of_cl_tuple_type(cl_type_array),
141                CLType::Tuple2(cl_type_array) => serialized_length_of_cl_tuple_type(cl_type_array),
142                CLType::Tuple3(cl_type_array) => serialized_length_of_cl_tuple_type(cl_type_array),
143            }
144    }
145
146    /// Returns `true` if the [`CLType`] is [`Option`].
147    pub fn is_option(&self) -> bool {
148        matches!(self, Self::Option(..))
149    }
150
151    /// Creates a `CLType::Map`.
152    pub fn map(key: CLType, value: CLType) -> Self {
153        CLType::Map {
154            key: Box::new(key),
155            value: Box::new(value),
156        }
157    }
158}
159
160/// Returns the `CLType` describing a "named key" on the system, i.e. a `(String, Key)`.
161pub fn named_key_type() -> CLType {
162    CLType::Tuple2([Box::new(CLType::String), Box::new(CLType::Key)])
163}
164
165impl CLType {
166    pub(crate) fn append_bytes(&self, stream: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
167        match self {
168            CLType::Bool => stream.push(CL_TYPE_TAG_BOOL),
169            CLType::I32 => stream.push(CL_TYPE_TAG_I32),
170            CLType::I64 => stream.push(CL_TYPE_TAG_I64),
171            CLType::U8 => stream.push(CL_TYPE_TAG_U8),
172            CLType::U32 => stream.push(CL_TYPE_TAG_U32),
173            CLType::U64 => stream.push(CL_TYPE_TAG_U64),
174            CLType::U128 => stream.push(CL_TYPE_TAG_U128),
175            CLType::U256 => stream.push(CL_TYPE_TAG_U256),
176            CLType::U512 => stream.push(CL_TYPE_TAG_U512),
177            CLType::Unit => stream.push(CL_TYPE_TAG_UNIT),
178            CLType::String => stream.push(CL_TYPE_TAG_STRING),
179            CLType::Key => stream.push(CL_TYPE_TAG_KEY),
180            CLType::URef => stream.push(CL_TYPE_TAG_UREF),
181            CLType::PublicKey => stream.push(CL_TYPE_TAG_PUBLIC_KEY),
182            CLType::Option(cl_type) => {
183                stream.push(CL_TYPE_TAG_OPTION);
184                cl_type.append_bytes(stream)?;
185            }
186            CLType::List(cl_type) => {
187                stream.push(CL_TYPE_TAG_LIST);
188                cl_type.append_bytes(stream)?;
189            }
190            CLType::ByteArray(len) => {
191                stream.push(CL_TYPE_TAG_BYTE_ARRAY);
192                stream.append(&mut len.to_bytes()?);
193            }
194            CLType::Result { ok, err } => {
195                stream.push(CL_TYPE_TAG_RESULT);
196                ok.append_bytes(stream)?;
197                err.append_bytes(stream)?;
198            }
199            CLType::Map { key, value } => {
200                stream.push(CL_TYPE_TAG_MAP);
201                key.append_bytes(stream)?;
202                value.append_bytes(stream)?;
203            }
204            CLType::Tuple1(cl_type_array) => {
205                serialize_cl_tuple_type(CL_TYPE_TAG_TUPLE1, cl_type_array, stream)?
206            }
207            CLType::Tuple2(cl_type_array) => {
208                serialize_cl_tuple_type(CL_TYPE_TAG_TUPLE2, cl_type_array, stream)?
209            }
210            CLType::Tuple3(cl_type_array) => {
211                serialize_cl_tuple_type(CL_TYPE_TAG_TUPLE3, cl_type_array, stream)?
212            }
213            CLType::Any => stream.push(CL_TYPE_TAG_ANY),
214        }
215        Ok(())
216    }
217}
218
219impl Display for CLType {
220    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
221        match self {
222            CLType::Bool => write!(formatter, "bool"),
223            CLType::I32 => write!(formatter, "i32"),
224            CLType::I64 => write!(formatter, "i64"),
225            CLType::U8 => write!(formatter, "u8"),
226            CLType::U32 => write!(formatter, "u32"),
227            CLType::U64 => write!(formatter, "u64"),
228            CLType::U128 => write!(formatter, "u128"),
229            CLType::U256 => write!(formatter, "u256"),
230            CLType::U512 => write!(formatter, "u512"),
231            CLType::Unit => write!(formatter, "unit"),
232            CLType::String => write!(formatter, "string"),
233            CLType::Key => write!(formatter, "key"),
234            CLType::URef => write!(formatter, "uref"),
235            CLType::PublicKey => write!(formatter, "public-key"),
236            CLType::Option(t) => write!(formatter, "option<{t}>"),
237            CLType::List(t) => write!(formatter, "list<{t}>"),
238            CLType::ByteArray(len) => write!(formatter, "byte-array[{len}]"),
239            CLType::Result { ok, err } => write!(formatter, "result<{ok}, {err}>"),
240            CLType::Map { key, value } => write!(formatter, "map<{key}, {value}>"),
241            CLType::Tuple1([t1]) => write!(formatter, "({t1},)"),
242            CLType::Tuple2([t1, t2]) => write!(formatter, "({t1}, {t2})"),
243            CLType::Tuple3([t1, t2, t3]) => write!(formatter, "({t1}, {t2}, {t3})"),
244            CLType::Any => write!(formatter, "any"),
245        }
246    }
247}
248
249impl FromBytes for CLType {
250    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
251        depth_limited_from_bytes(0, bytes)
252    }
253}
254
255fn depth_limited_from_bytes(depth: u8, bytes: &[u8]) -> Result<(CLType, &[u8]), bytesrepr::Error> {
256    if depth >= CL_TYPE_RECURSION_DEPTH {
257        return Err(bytesrepr::Error::ExceededRecursionDepth);
258    }
259    let depth = depth + 1;
260    let (tag, remainder) = u8::from_bytes(bytes)?;
261    match tag {
262        CL_TYPE_TAG_BOOL => Ok((CLType::Bool, remainder)),
263        CL_TYPE_TAG_I32 => Ok((CLType::I32, remainder)),
264        CL_TYPE_TAG_I64 => Ok((CLType::I64, remainder)),
265        CL_TYPE_TAG_U8 => Ok((CLType::U8, remainder)),
266        CL_TYPE_TAG_U32 => Ok((CLType::U32, remainder)),
267        CL_TYPE_TAG_U64 => Ok((CLType::U64, remainder)),
268        CL_TYPE_TAG_U128 => Ok((CLType::U128, remainder)),
269        CL_TYPE_TAG_U256 => Ok((CLType::U256, remainder)),
270        CL_TYPE_TAG_U512 => Ok((CLType::U512, remainder)),
271        CL_TYPE_TAG_UNIT => Ok((CLType::Unit, remainder)),
272        CL_TYPE_TAG_STRING => Ok((CLType::String, remainder)),
273        CL_TYPE_TAG_KEY => Ok((CLType::Key, remainder)),
274        CL_TYPE_TAG_UREF => Ok((CLType::URef, remainder)),
275        CL_TYPE_TAG_PUBLIC_KEY => Ok((CLType::PublicKey, remainder)),
276        CL_TYPE_TAG_OPTION => {
277            let (inner_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
278            let cl_type = CLType::Option(Box::new(inner_type));
279            Ok((cl_type, remainder))
280        }
281        CL_TYPE_TAG_LIST => {
282            let (inner_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
283            let cl_type = CLType::List(Box::new(inner_type));
284            Ok((cl_type, remainder))
285        }
286        CL_TYPE_TAG_BYTE_ARRAY => {
287            let (len, remainder) = u32::from_bytes(remainder)?;
288            let cl_type = CLType::ByteArray(len);
289            Ok((cl_type, remainder))
290        }
291        CL_TYPE_TAG_RESULT => {
292            let (ok_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
293            let (err_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
294            let cl_type = CLType::Result {
295                ok: Box::new(ok_type),
296                err: Box::new(err_type),
297            };
298            Ok((cl_type, remainder))
299        }
300        CL_TYPE_TAG_MAP => {
301            let (key_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
302            let (value_type, remainder) = depth_limited_from_bytes(depth, remainder)?;
303            let cl_type = CLType::Map {
304                key: Box::new(key_type),
305                value: Box::new(value_type),
306            };
307            Ok((cl_type, remainder))
308        }
309        CL_TYPE_TAG_TUPLE1 => {
310            let (mut inner_types, remainder) = parse_cl_tuple_types(depth, 1, remainder)?;
311            // NOTE: Assumed safe as `parse_cl_tuple_types` is expected to have exactly 1
312            // element
313            let cl_type = CLType::Tuple1([inner_types.pop_front().unwrap()]);
314            Ok((cl_type, remainder))
315        }
316        CL_TYPE_TAG_TUPLE2 => {
317            let (mut inner_types, remainder) = parse_cl_tuple_types(depth, 2, remainder)?;
318            // NOTE: Assumed safe as `parse_cl_tuple_types` is expected to have exactly 2
319            // elements
320            let cl_type = CLType::Tuple2([
321                inner_types.pop_front().unwrap(),
322                inner_types.pop_front().unwrap(),
323            ]);
324            Ok((cl_type, remainder))
325        }
326        CL_TYPE_TAG_TUPLE3 => {
327            let (mut inner_types, remainder) = parse_cl_tuple_types(depth, 3, remainder)?;
328            // NOTE: Assumed safe as `parse_cl_tuple_types` is expected to have exactly 3
329            // elements
330            let cl_type = CLType::Tuple3([
331                inner_types.pop_front().unwrap(),
332                inner_types.pop_front().unwrap(),
333                inner_types.pop_front().unwrap(),
334            ]);
335            Ok((cl_type, remainder))
336        }
337        CL_TYPE_TAG_ANY => Ok((CLType::Any, remainder)),
338        _ => Err(bytesrepr::Error::Formatting),
339    }
340}
341
342fn serialize_cl_tuple_type<'a, T: IntoIterator<Item = &'a Box<CLType>>>(
343    tag: u8,
344    cl_type_array: T,
345    stream: &mut Vec<u8>,
346) -> Result<(), bytesrepr::Error> {
347    stream.push(tag);
348    for cl_type in cl_type_array {
349        cl_type.append_bytes(stream)?;
350    }
351    Ok(())
352}
353
354fn parse_cl_tuple_types(
355    depth: u8,
356    count: usize,
357    mut bytes: &[u8],
358) -> Result<(VecDeque<Box<CLType>>, &[u8]), bytesrepr::Error> {
359    let mut cl_types = VecDeque::with_capacity(count);
360    for _ in 0..count {
361        let (cl_type, remainder) = depth_limited_from_bytes(depth, bytes)?;
362        cl_types.push_back(Box::new(cl_type));
363        bytes = remainder;
364    }
365
366    Ok((cl_types, bytes))
367}
368
369fn serialized_length_of_cl_tuple_type<'a, T: IntoIterator<Item = &'a Box<CLType>>>(
370    cl_type_array: T,
371) -> usize {
372    cl_type_array
373        .into_iter()
374        .map(|cl_type| cl_type.serialized_length())
375        .sum()
376}
377
378/// A type which can be described as a [`CLType`].
379pub trait CLTyped {
380    /// The `CLType` of `Self`.
381    fn cl_type() -> CLType;
382}
383
384impl CLTyped for bool {
385    fn cl_type() -> CLType {
386        CLType::Bool
387    }
388}
389
390impl CLTyped for i32 {
391    fn cl_type() -> CLType {
392        CLType::I32
393    }
394}
395
396impl CLTyped for i64 {
397    fn cl_type() -> CLType {
398        CLType::I64
399    }
400}
401
402impl CLTyped for u8 {
403    fn cl_type() -> CLType {
404        CLType::U8
405    }
406}
407
408impl CLTyped for u32 {
409    fn cl_type() -> CLType {
410        CLType::U32
411    }
412}
413
414impl CLTyped for u64 {
415    fn cl_type() -> CLType {
416        CLType::U64
417    }
418}
419
420impl CLTyped for U128 {
421    fn cl_type() -> CLType {
422        CLType::U128
423    }
424}
425
426impl CLTyped for U256 {
427    fn cl_type() -> CLType {
428        CLType::U256
429    }
430}
431
432impl CLTyped for U512 {
433    fn cl_type() -> CLType {
434        CLType::U512
435    }
436}
437
438impl CLTyped for () {
439    fn cl_type() -> CLType {
440        CLType::Unit
441    }
442}
443
444impl CLTyped for String {
445    fn cl_type() -> CLType {
446        CLType::String
447    }
448}
449
450impl CLTyped for &str {
451    fn cl_type() -> CLType {
452        CLType::String
453    }
454}
455
456impl CLTyped for Key {
457    fn cl_type() -> CLType {
458        CLType::Key
459    }
460}
461
462impl CLTyped for URef {
463    fn cl_type() -> CLType {
464        CLType::URef
465    }
466}
467
468impl<T: CLTyped> CLTyped for Option<T> {
469    fn cl_type() -> CLType {
470        CLType::Option(Box::new(T::cl_type()))
471    }
472}
473
474impl<T: CLTyped> CLTyped for Vec<T> {
475    fn cl_type() -> CLType {
476        CLType::List(Box::new(T::cl_type()))
477    }
478}
479
480impl<T: CLTyped> CLTyped for BTreeSet<T> {
481    fn cl_type() -> CLType {
482        CLType::List(Box::new(T::cl_type()))
483    }
484}
485
486impl<T: CLTyped> CLTyped for &T {
487    fn cl_type() -> CLType {
488        T::cl_type()
489    }
490}
491
492impl<const COUNT: usize> CLTyped for [u8; COUNT] {
493    fn cl_type() -> CLType {
494        CLType::ByteArray(COUNT as u32)
495    }
496}
497
498impl<T: CLTyped, E: CLTyped> CLTyped for Result<T, E> {
499    fn cl_type() -> CLType {
500        let ok = Box::new(T::cl_type());
501        let err = Box::new(E::cl_type());
502        CLType::Result { ok, err }
503    }
504}
505
506impl<K: CLTyped, V: CLTyped> CLTyped for BTreeMap<K, V> {
507    fn cl_type() -> CLType {
508        let key = Box::new(K::cl_type());
509        let value = Box::new(V::cl_type());
510        CLType::Map { key, value }
511    }
512}
513
514impl<T1: CLTyped> CLTyped for (T1,) {
515    fn cl_type() -> CLType {
516        CLType::Tuple1([Box::new(T1::cl_type())])
517    }
518}
519
520impl<T1: CLTyped, T2: CLTyped> CLTyped for (T1, T2) {
521    fn cl_type() -> CLType {
522        CLType::Tuple2([Box::new(T1::cl_type()), Box::new(T2::cl_type())])
523    }
524}
525
526impl<T1: CLTyped, T2: CLTyped, T3: CLTyped> CLTyped for (T1, T2, T3) {
527    fn cl_type() -> CLType {
528        CLType::Tuple3([
529            Box::new(T1::cl_type()),
530            Box::new(T2::cl_type()),
531            Box::new(T3::cl_type()),
532        ])
533    }
534}
535
536impl<T: CLTyped> CLTyped for Ratio<T> {
537    fn cl_type() -> CLType {
538        <(T, T)>::cl_type()
539    }
540}
541
542#[cfg(test)]
543mod tests {
544    use std::{fmt::Debug, iter, string::ToString};
545
546    use super::*;
547    use crate::{
548        bytesrepr::{FromBytes, ToBytes},
549        AccessRights, CLValue,
550    };
551
552    fn round_trip<T: CLTyped + FromBytes + ToBytes + PartialEq + Debug>(value: &T) {
553        let cl_value = CLValue::from_t(value).unwrap();
554
555        let serialized_cl_value = cl_value.to_bytes().unwrap();
556        assert_eq!(serialized_cl_value.len(), cl_value.serialized_length());
557        let parsed_cl_value: CLValue = bytesrepr::deserialize(serialized_cl_value).unwrap();
558        assert_eq!(cl_value, parsed_cl_value);
559
560        let parsed_value = cl_value.into_t().unwrap();
561        assert_eq!(*value, parsed_value);
562    }
563
564    #[test]
565    fn bool_should_work() {
566        round_trip(&true);
567        round_trip(&false);
568    }
569
570    #[test]
571    fn u8_should_work() {
572        round_trip(&1u8);
573    }
574
575    #[test]
576    fn u32_should_work() {
577        round_trip(&1u32);
578    }
579
580    #[test]
581    fn i32_should_work() {
582        round_trip(&-1i32);
583    }
584
585    #[test]
586    fn u64_should_work() {
587        round_trip(&1u64);
588    }
589
590    #[test]
591    fn i64_should_work() {
592        round_trip(&-1i64);
593    }
594
595    #[test]
596    fn u128_should_work() {
597        round_trip(&U128::one());
598    }
599
600    #[test]
601    fn u256_should_work() {
602        round_trip(&U256::one());
603    }
604
605    #[test]
606    fn u512_should_work() {
607        round_trip(&U512::one());
608    }
609
610    #[test]
611    fn unit_should_work() {
612        round_trip(&());
613    }
614
615    #[test]
616    fn string_should_work() {
617        round_trip(&String::from("abc"));
618    }
619
620    #[test]
621    fn key_should_work() {
622        let key = Key::URef(URef::new([0u8; 32], AccessRights::READ_ADD_WRITE));
623        round_trip(&key);
624    }
625
626    #[test]
627    fn uref_should_work() {
628        let uref = URef::new([0u8; 32], AccessRights::READ_ADD_WRITE);
629        round_trip(&uref);
630    }
631
632    #[test]
633    fn option_of_cl_type_should_work() {
634        let x: Option<i32> = Some(-1);
635        let y: Option<i32> = None;
636
637        round_trip(&x);
638        round_trip(&y);
639    }
640
641    #[test]
642    fn vec_of_cl_type_should_work() {
643        let vec = vec![String::from("a"), String::from("b")];
644        round_trip(&vec);
645    }
646
647    #[test]
648    #[allow(clippy::cognitive_complexity)]
649    fn small_array_of_u8_should_work() {
650        macro_rules! test_small_array {
651            ($($N:literal)+) => {
652                $(
653                    let mut array: [u8; $N] = Default::default();
654                    for i in 0..$N {
655                        array[i] = i as u8;
656                    }
657                    round_trip(&array);
658                )+
659            }
660        }
661
662        test_small_array! {
663                 1  2  3  4  5  6  7  8  9
664             10 11 12 13 14 15 16 17 18 19
665             20 21 22 23 24 25 26 27 28 29
666             30 31 32
667        }
668    }
669
670    #[test]
671    fn large_array_of_cl_type_should_work() {
672        macro_rules! test_large_array {
673            ($($N:literal)+) => {
674                $(
675                    let array = {
676                        let mut tmp = [0u8; $N];
677                        for i in 0..$N {
678                            tmp[i] = i as u8;
679                        }
680                        tmp
681                    };
682
683                    let cl_value = CLValue::from_t(array.clone()).unwrap();
684
685                    let serialized_cl_value = cl_value.to_bytes().unwrap();
686                    let parsed_cl_value: CLValue = bytesrepr::deserialize(serialized_cl_value).unwrap();
687                    assert_eq!(cl_value, parsed_cl_value);
688
689                    let parsed_value: [u8; $N] = CLValue::into_t(cl_value).unwrap();
690                    for i in 0..$N {
691                        assert_eq!(array[i], parsed_value[i]);
692                    }
693                )+
694            }
695        }
696
697        test_large_array! { 64 128 256 512 }
698    }
699
700    #[test]
701    fn result_of_cl_type_should_work() {
702        let x: Result<(), String> = Ok(());
703        let y: Result<(), String> = Err(String::from("Hello, world!"));
704
705        round_trip(&x);
706        round_trip(&y);
707    }
708
709    #[test]
710    fn map_of_cl_type_should_work() {
711        let mut map: BTreeMap<String, u64> = BTreeMap::new();
712        map.insert(String::from("abc"), 1);
713        map.insert(String::from("xyz"), 2);
714
715        round_trip(&map);
716    }
717
718    #[test]
719    fn tuple_1_should_work() {
720        let x = (-1i32,);
721
722        round_trip(&x);
723    }
724
725    #[test]
726    fn tuple_2_should_work() {
727        let x = (-1i32, String::from("a"));
728
729        round_trip(&x);
730    }
731
732    #[test]
733    fn tuple_3_should_work() {
734        let x = (-1i32, 1u32, String::from("a"));
735
736        round_trip(&x);
737    }
738
739    #[test]
740    fn parsing_nested_tuple_1_cltype_should_not_stack_overflow() {
741        // The bytesrepr representation of the CLType for a
742        // nested (((...((),),...),),) looks like:
743        // [18, 18, 18, ..., 9]
744
745        for i in 1..1000 {
746            let bytes = iter::repeat(CL_TYPE_TAG_TUPLE1)
747                .take(i)
748                .chain(iter::once(CL_TYPE_TAG_UNIT))
749                .collect();
750            match bytesrepr::deserialize(bytes) {
751                Ok(parsed_cltype) => assert!(matches!(parsed_cltype, CLType::Tuple1(_))),
752                Err(error) => assert_eq!(error, bytesrepr::Error::ExceededRecursionDepth),
753            }
754        }
755    }
756
757    #[test]
758    fn parsing_nested_tuple_1_value_should_not_stack_overflow() {
759        // The bytesrepr representation of the CLValue for a
760        // nested (((...((),),...),),) looks like:
761        // [0, 0, 0, 0, 18, 18, 18, ..., 18, 9]
762
763        for i in 1..1000 {
764            let bytes = iter::repeat(0)
765                .take(4)
766                .chain(iter::repeat(CL_TYPE_TAG_TUPLE1).take(i))
767                .chain(iter::once(CL_TYPE_TAG_UNIT))
768                .collect();
769            match bytesrepr::deserialize::<CLValue>(bytes) {
770                Ok(parsed_clvalue) => {
771                    assert!(matches!(parsed_clvalue.cl_type(), CLType::Tuple1(_)))
772                }
773                Err(error) => assert_eq!(error, bytesrepr::Error::ExceededRecursionDepth),
774            }
775        }
776    }
777
778    #[test]
779    fn any_should_work() {
780        #[derive(PartialEq, Debug, Clone)]
781        struct Any(String);
782
783        impl CLTyped for Any {
784            fn cl_type() -> CLType {
785                CLType::Any
786            }
787        }
788
789        impl ToBytes for Any {
790            fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
791                self.0.to_bytes()
792            }
793
794            fn serialized_length(&self) -> usize {
795                self.0.serialized_length()
796            }
797        }
798
799        impl FromBytes for Any {
800            fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
801                let (inner, remainder) = String::from_bytes(bytes)?;
802                Ok((Any(inner), remainder))
803            }
804        }
805
806        let any = Any("Any test".to_string());
807        round_trip(&any);
808    }
809
810    #[test]
811    fn should_have_cltype_of_ref_to_cltyped() {
812        assert_eq!(<Vec<&u64>>::cl_type(), <Vec<u64>>::cl_type())
813    }
814}