casper_types/
cl_type.rs

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