candy_rs/
value.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt::Display;
3use std::hash::Hash;
4
5use candid::{CandidType, Deserialize, Encode, Principal};
6use hex::ToHex;
7use num_bigint::{BigInt, BigUint};
8use num_traits::cast::ToPrimitive;
9use num_traits::Signed;
10use serde::Serialize;
11
12use crate::types::PropertyShared;
13
14/**
15 * `CandyShared` is a Rust enum that provides a wrapper type for convenient data manipulation inside ICP canisters.
16 * This enum includes various data types that can be used for communication between canisters, including integers, floats, text, boolean, and more.
17 *
18 */
19#[derive(CandidType, Debug, Serialize, Deserialize, Clone)]
20pub enum CandyShared {
21    Int(candid::Int),
22    Int8(i8),
23    Int16(i16),
24    Int32(i32),
25    Int64(i64),
26    Ints(Vec<candid::Int>),
27    Nat(candid::Nat),
28    Nat8(u8),
29    Nat16(u16),
30    Nat32(u32),
31    Nat64(u64),
32    Float(f64),
33    Text(String),
34    Bool(bool),
35    Blob(Vec<u8>),
36    Bytes(Vec<u8>),
37    Class(Vec<PropertyShared>),
38    Principal(Principal),
39    Option(Option<Box<CandyShared>>),
40    Array(Vec<CandyShared>),
41    Nats(Vec<candid::Nat>),
42    Floats(Vec<f64>),
43    Map(HashMap<CandyShared, CandyShared>),
44    Set(HashSet<CandyShared>),
45}
46
47macro_rules! to_nat_of_size {
48    ($x:tt, $method: ident) => {
49        match $x {
50            Self::Nat(val) => val.0.$method(),
51            Self::Nat8(val) => val.$method(),
52            Self::Nat16(val) => val.$method(),
53            Self::Nat32(val) => val.$method(),
54            Self::Nat64(val) => val.$method(),
55            Self::Float(val) => match val {
56                val if val < 0.0 => None,
57                _ => val.round().$method(),
58            },
59            Self::Int(val) => val.0.$method(),
60            Self::Int8(val) => val.$method(),
61            Self::Int16(val) => val.$method(),
62            Self::Int32(val) => val.$method(),
63            Self::Int64(val) => val.$method(),
64            _ => None,
65        }
66    };
67}
68
69macro_rules! to_int_of_size {
70    ($x:tt, $method: ident) => {
71        match $x {
72            Self::Nat(val) => val.0.$method(),
73            Self::Nat8(val) => val.$method(),
74            Self::Nat16(val) => val.$method(),
75            Self::Nat32(val) => val.$method(),
76            Self::Nat64(val) => val.$method(),
77            Self::Float(val) => val.round().$method(),
78            Self::Int(val) => val.0.$method(),
79            Self::Int8(val) => val.$method(),
80            Self::Int16(val) => val.$method(),
81            Self::Int32(val) => val.$method(),
82            Self::Int64(val) => val.$method(),
83            _ => None,
84        }
85    };
86}
87
88impl CandyShared {
89    /**
90     * `to_nat` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a natural number of size `u128`.
91     * This method uses the `to_nat_of_size!` macro to perform the conversion.
92     *
93     * # Examples
94     *
95     * ```
96     * use candy::value::{CandyShared, ToCandyValue};
97     *
98     * let value = 42_u128.to_candy();
99     * let result = value.to_nat();
100     * assert_eq!(result, Some(42));
101     * ```
102     */
103    pub fn to_nat(self) -> Option<u128> {
104        to_nat_of_size!(self, to_u128)
105    }
106
107    /**
108     * `to_nat8` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to an 8-bit natural number (`u8`).
109     * This method uses the `to_nat_of_size!` macro to perform the conversion.
110     *
111     * # Examples
112     *
113     * ```
114     * use candy::value::{CandyShared, ToCandyValue};
115     *
116     * let value = 420000_u128.to_candy();
117     * let result = value.to_nat8();
118     * assert_eq!(result, None);
119     *
120     * let value = 42_u8.to_candy();
121     * let result = value.to_nat8();
122     * assert_eq!(result, Some(42));
123     * ```
124     */
125    pub fn to_nat8(self) -> Option<u8> {
126        to_nat_of_size!(self, to_u8)
127    }
128
129    /**
130     * `to_nat16` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a natural number of size `u16`.
131     * This method uses the `to_nat_of_size!` macro to perform the conversion.
132     *
133     * # Examples
134     *
135     * ```
136     * use candy::value::{CandyShared,ToCandyValue};
137     *
138     * let value = 42_u16.to_candy();
139     * let result = value.to_nat16();
140     * assert_eq!(result, Some(42));
141     * ```
142     */
143    pub fn to_nat16(self) -> Option<u16> {
144        to_nat_of_size!(self, to_u16)
145    }
146
147    /**
148     * `to_nat32` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a natural number of size `u32`.
149     * This method uses the `to_nat_of_size!` macro to perform the conversion.
150     *
151     * # Examples
152     *
153     * ```
154     * use candy::value::{CandyShared,ToCandyValue};
155     *
156     * let value = 42_u32.to_candy();
157     * let result = value.to_nat32();
158     * assert_eq!(result, Some(42));
159     * ```
160     */
161    pub fn to_nat32(self) -> Option<u32> {
162        to_nat_of_size!(self, to_u32)
163    }
164
165    /**
166     * `to_nat64` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a natural number of size `u64`.
167     * This method returns an `Option<u64>` that contains the resulting `u64` value if the conversion is successful, and `None` otherwise.
168     *
169     * # Examples
170     *
171     * ```
172     * use candy::value::{CandyShared, ToCandyValue};
173     *
174     * let value = 42_u128.to_candy();
175     * let result = value.to_nat64();
176     * assert_eq!(result, Some(42));
177     * ```
178     */
179    pub fn to_nat64(self) -> Option<u64> {
180        to_nat_of_size!(self, to_u64)
181    }
182
183    /**
184     * `to_int` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a signed integer of size `i128`.
185     * This method uses the `to_int_of_size!` macro to perform the conversion.
186     *
187     * # Examples
188     *
189     * ```
190     * use candy::value::{CandyShared, ToCandyValue};
191     *
192     * let value = 42_u128.to_candy();
193     * let result = value.to_int();
194     * assert_eq!(result, Some(42));
195     * ```
196     */
197    pub fn to_int(self) -> Option<i128> {
198        to_int_of_size!(self, to_i128)
199    }
200
201    /**
202     * `to_int8` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to an `i8` signed integer.
203     * This method returns an `Option<i8>` that contains the resulting `i8` value if the conversion is successful, and `None` otherwise.
204     *
205     * # Examples
206     *
207     * ```
208     * use candy::value::{CandyShared,ToCandyValue};
209     *
210     * let value = 42_u128.to_candy();
211     * let result = value.to_int8();
212     * assert_eq!(result, Some(42));
213     * ```
214     */
215    pub fn to_int8(self) -> Option<i8> {
216        to_int_of_size!(self, to_i8)
217    }
218
219    /**
220     * `to_int16` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a signed 16-bit integer (`i16`).
221     * This method returns an `Option<i16>` that contains the resulting `i16` value if the conversion is successful, and `None` otherwise.
222     *
223     * # Examples
224     *
225     * ```
226     * use candy::value::{CandyShared, ToCandyValue};
227     *
228     * let value = 42_i128.to_candy();
229     * let result = value.to_int16();
230     * assert_eq!(result, Some(42));
231     *
232     * let value = (-32768_i64).to_candy();
233     * let result = value.to_int16();
234     * assert_eq!(result, Some(-32768));
235     * ```
236     */
237    pub fn to_int16(self) -> Option<i16> {
238        to_int_of_size!(self, to_i16)
239    }
240
241    /**
242     * `to_int32` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a 32-bit signed integer.
243     * This method returns an `Option<i32>` that contains the resulting `i32` value if the conversion is successful, and `None` otherwise.
244     *
245     * # Examples
246     *
247     * ```
248     * use candy::value::{CandyShared, ToCandyValue};
249     *
250     * let value = 42_i128.to_candy();
251     * let result = value.to_int32();
252     * assert_eq!(result, Some(42));
253     * ```
254     */
255    pub fn to_int32(self) -> Option<i32> {
256        to_int_of_size!(self, to_i32)
257    }
258
259    /**
260     * `to_int64` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a signed integer of size `i64`.
261     * This method uses the `to_int_of_size!` macro to perform the conversion.
262     *
263     * # Examples
264     *
265     * ```
266     * use candy::value::{CandyShared, ToCandyValue};
267     *
268     * let value = 42_i64.to_candy();
269     * let result = value.to_int64();
270     * assert_eq!(result, Some(42));
271     * ```
272     */
273    pub fn to_int64(self) -> Option<i64> {
274        to_int_of_size!(self, to_i64)
275    }
276
277    /**
278     * `to_float` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a `f64` floating-point number.
279     * This method returns an `Option<f64>` that contains the resulting `f64` value if the conversion is successful, and `None` otherwise.
280     *
281     * # Examples
282     *
283     * ```
284     * use candy::value::{CandyShared,ToCandyValue};
285     *
286     * let value = 42_u128.to_candy();
287     * let result = value.to_float();
288     * assert_eq!(result, Some(42.0));
289     * ```
290     */
291    pub fn to_float(self) -> Option<f64> {
292        match self {
293            Self::Nat(val) => val.0.to_f64(),
294            Self::Nat8(val) => val.to_f64(),
295            Self::Nat16(val) => val.to_f64(),
296            Self::Nat32(val) => val.to_f64(),
297            Self::Nat64(val) => val.to_f64(),
298            Self::Float(val) => Some(val),
299            Self::Int(val) => val.0.to_f64(),
300            Self::Int8(val) => val.to_f64(),
301            Self::Int16(val) => val.to_f64(),
302            Self::Int32(val) => val.to_f64(),
303            Self::Int64(val) => val.to_f64(),
304            _ => None,
305        }
306    }
307
308    /**
309     * `to_bool` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a `bool` boolean.
310     * This method returns an `Option<bool>` that contains the resulting `bool` value if the conversion is successful, and `None` otherwise.
311     *
312     * # Examples
313     *
314     * ```
315     * use candy::value::{CandyShared, ToCandyValue};
316     *
317     * let value = true.to_candy();
318     * let result = value.to_bool();
319     * assert_eq!(result, Some(true));
320     * ```
321     */
322    pub fn to_bool(self) -> Option<bool> {
323        match self {
324            Self::Bool(val) => Some(val),
325            _ => None,
326        }
327    }
328
329    /**
330     * `to_principal` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a `Principal`.
331     * This method returns an `Option<Principal>` that contains the resulting `Principal` value if the conversion is successful, and `None` otherwise.
332     *
333     * # Examples
334     *
335     * ```
336     * use candy::value::{CandyShared, ToCandyValue};
337     * use candid::Principal;
338     *
339     * let principal = Principal::anonymous();
340     * let value = principal.clone().to_candy();
341     * let result = value.to_principal();
342     * assert_eq!(result, Some(principal));
343     * ```
344     */
345    pub fn to_principal(self) -> Option<Principal> {
346        match self {
347            Self::Principal(val) => Some(val),
348            _ => None,
349        }
350    }
351
352    /**
353     * `to_blob` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a `Vec<u8>` blob.
354     * This method returns a `Vec<u8>` that contains the binary representation of the value.
355     *
356     * # Examples
357     *
358     * ```
359     * use candy::value::{CandyShared,ToCandyValue};
360     *
361     * let value = "Hello, world!".to_candy();
362     * let result = value.to_blob();
363     * assert_eq!(result, vec![0, 0, 0, 72, 0, 0, 0, 101, 0, 0, 0, 108, 0, 0, 0, 108, 0, 0, 0, 111, 0, 0, 0, 44, 0, 0, 0, 32, 0, 0, 0, 119, 0, 0, 0, 111, 0, 0, 0, 114, 0, 0, 0, 108, 0, 0, 0, 100, 0, 0, 0, 33]);
364     * ```
365     */
366    pub fn to_blob(self) -> Vec<u8> {
367        match self {
368            Self::Blob(val) => val,
369            Self::Bytes(val) => val,
370            Self::Text(val) => val.chars().flat_map(|c| (c as u32).to_be_bytes()).collect(),
371            Self::Int(val) => val.0.to_blob(),
372            Self::Nat(val) => val.0.to_blob(),
373            Self::Nat8(val) => [val].to_vec(),
374            Self::Nat16(val) => val.to_be_bytes().to_vec(),
375            Self::Nat32(val) => val.to_be_bytes().to_vec(),
376            Self::Nat64(val) => val.to_be_bytes().to_vec(),
377            Self::Principal(val) => val.as_slice().into(),
378            _ => ic_cdk::trap(format!("Cannot convert to blob {}", self).as_str()),
379        }
380    }
381
382    /**
383     * `to_json` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a JSON string.
384     * This method returns a `String` that represents the resulting JSON.
385     *
386     * # Examples
387     *
388     * ```
389     * use candy::value::{CandyShared,ToCandyValue};
390     *
391     * let value = 42_u128.to_candy();
392     * let result = value.to_json();
393     * assert_eq!(result, "42".to_string());
394     * ```
395     */
396    pub fn to_json(self) -> String {
397        match self {
398            Self::Nat(val) => val.to_string(),
399            Self::Nat8(val) => val.to_string(),
400            Self::Nat16(val) => val.to_string(),
401            Self::Nat32(val) => val.to_string(),
402            Self::Nat64(val) => val.to_string(),
403            Self::Int(val) => val.to_string(),
404            Self::Int8(val) => val.to_string(),
405            Self::Int16(val) => val.to_string(),
406            Self::Int32(val) => val.to_string(),
407            Self::Int64(val) => val.to_string(),
408            Self::Float(val) => val.to_string(),
409            Self::Text(val) => serde_json::to_string(&val).unwrap(),
410            Self::Class(val) => PropertyShared::props_to_json(&val),
411            Self::Array(val) => format!(
412                "[{}]",
413                val.iter()
414                    .map(|i| i.clone().to_json())
415                    .collect::<Vec<String>>()
416                    .join(",")
417            ),
418            Self::Option(val) => match val {
419                Some(val) => val.to_json(),
420                None => "null".to_string(),
421            },
422            Self::Nats(val) => format!(
423                "[{}]",
424                val.iter()
425                    .map(|i| i.to_string())
426                    .collect::<Vec<String>>()
427                    .join(",")
428            ),
429            Self::Ints(val) => format!(
430                "[{}]",
431                val.iter()
432                    .map(|i| i.to_string())
433                    .collect::<Vec<String>>()
434                    .join(",")
435            ),
436            Self::Floats(val) => format!(
437                "[{}]",
438                val.iter()
439                    .map(|i| i.to_string())
440                    .collect::<Vec<String>>()
441                    .join(",")
442            ),
443            Self::Bytes(val) => format!("\"{}\"", val.encode_hex::<String>()),
444            Self::Blob(val) => format!("\"{}\"", val.encode_hex::<String>()),
445            Self::Principal(val) => format!("\"{}\"", val),
446            Self::Bool(val) => format!("\"{}\"", val),
447            _ => "".to_string(),
448        }
449    }
450
451    /**
452     * `to_value_array` is a method defined on the `CandyShared` Rust enum that provides a convenient way to convert a value to a `Vec<CandyShared>` array.
453     * This method returns an `Option<Vec<CandyShared>>` that contains the resulting array if the conversion is successful, and `None` otherwise.
454     *
455     * # Examples
456     *
457     * ```
458     * use candy::value::{CandyShared,ToCandyValue};
459     *
460     * let arr = vec![42_u128.to_candy(), 50_u128.to_candy()];
461     * let value = CandyShared::Array(arr);
462     * let result = value.to_value_array();
463     * assert_eq!(result, Some(vec![42_u128.to_candy(), 50_u128.to_candy()]));
464     * ```
465     */
466    pub fn to_value_array(self) -> Option<Vec<CandyShared>> {
467        match self {
468            Self::Array(val) => Some(val),
469            _ => None,
470        }
471    }
472
473    // Return the size of the value in bytes
474    ///
475    /// ```
476    /// use candy::value::CandyShared;
477    /// use candy::workspace::DataZone;
478    /// use crate::candy::workspace::DataZoneTrait;
479    /// use crate::candy::value::ToCandyValue;
480    /// use candid::Principal;
481    ///
482    ///
483    /// let dz : CandyShared = vec![0_u8;3_000_000].to_candy();
484    /// assert_eq!(dz.get_value_size(),3000196);
485    /// ```
486    pub fn get_value_size(&self) -> u128 {
487        Encode!(self).unwrap().len() as u128
488    }
489
490    pub fn stringify_array_of_values(vals: &[CandyShared]) -> String {
491        let mut result = String::new();
492        result.push('[');
493        for value in vals {
494            let converted = format!("{{{}}} ", value.clone());
495            result.push_str(&converted);
496        }
497        let mut trimmed = result.trim_end().to_string();
498        trimmed.push(']');
499        trimmed
500    }
501}
502
503macro_rules! impl_from {
504    ($($t:ty => $v:ident),*) => {
505        $(impl From<$t> for CandyShared {
506            fn from(value: $t) -> Self {
507                CandyShared::$v(value)
508            }
509        })*
510    };
511}
512
513impl_from!(
514    i8 => Int8,
515    i16 => Int16,
516    i32 => Int32,
517    i64 => Int64,
518    u8 => Nat8,
519    u16 => Nat16,
520    u32 => Nat32,
521    u64 => Nat64,
522    f64 => Float
523);
524
525impl_from!(
526    String => Text,
527    bool => Bool,
528    Vec<PropertyShared> => Class,
529    Principal => Principal ,
530    Option<Box<CandyShared >> => Option,
531    Vec<u8> => Blob,
532    HashMap<CandyShared,CandyShared> => Map,
533    HashSet<CandyShared> => Set
534);
535
536impl From<u128> for CandyShared {
537    fn from(value: u128) -> Self {
538        CandyShared::Nat(candid::Nat::from(value))
539    }
540}
541
542impl From<BigInt> for CandyShared {
543    fn from(value: BigInt) -> Self {
544        CandyShared::Int(candid::Int::from(value))
545    }
546}
547
548impl From<BigUint> for CandyShared {
549    fn from(value: BigUint) -> Self {
550        CandyShared::Nat(candid::Nat::from(value))
551    }
552}
553
554impl From<i128> for CandyShared {
555    fn from(value: i128) -> Self {
556        CandyShared::Int(candid::Int::from(value))
557    }
558}
559
560impl From<&str> for CandyShared {
561    fn from(value: &str) -> Self {
562        CandyShared::Text(value.to_string())
563    }
564}
565
566impl From<Vec<CandyShared>> for CandyShared {
567    fn from(value: Vec<CandyShared>) -> Self {
568        CandyShared::Array(value)
569    }
570}
571
572impl From<Vec<candid::Nat>> for CandyShared {
573    fn from(value: Vec<candid::Nat>) -> Self {
574        CandyShared::Nats(value)
575    }
576}
577
578impl From<Vec<candid::Int>> for CandyShared {
579    fn from(value: Vec<candid::Int>) -> Self {
580        CandyShared::Ints(value)
581    }
582}
583
584impl From<Vec<u128>> for CandyShared {
585    fn from(value: Vec<u128>) -> Self {
586        CandyShared::Nats(value.into_iter().map(candid::Nat::from).collect())
587    }
588}
589
590impl From<Vec<i128>> for CandyShared {
591    fn from(value: Vec<i128>) -> Self {
592        CandyShared::Ints(value.into_iter().map(candid::Int::from).collect())
593    }
594}
595
596impl From<Vec<f64>> for CandyShared {
597    fn from(value: Vec<f64>) -> Self {
598        CandyShared::Floats(value)
599    }
600}
601
602/**
603 * `ToCandyValue` is a trait that defines a method `to_candy`, which is used to convert a value of any type into a `CandyShared` enum.
604 * This trait can be implemented by any type that can be converted into a `CandyShared` enum, allowing for seamless integration with the `CandyShared` type in Rust code.
605 *
606 * # Examples
607 *
608 * ```
609 * use crate::candy::value::{CandyShared, ToCandyValue};
610 *
611 * let value = 42u8;
612 * let result = value.to_candy();
613 * assert_eq!(result, CandyShared::Nat8(42));
614 * ```
615 */
616pub trait ToCandyValue {
617    fn to_candy(self) -> CandyShared;
618}
619
620macro_rules! to_candy {
621    ($($t:ty),*) => {
622        $(impl ToCandyValue for $t {
623            #[inline]
624            fn to_candy(self) -> CandyShared {
625                CandyShared::from(self)
626            }
627        })*
628    };
629}
630
631// Implementations
632to_candy!(
633    BigInt,
634    BigUint,
635    i128,
636    i8,
637    i16,
638    i32,
639    i64,
640    u128,
641    u8,
642    u16,
643    u32,
644    u64,
645    f64,
646    Vec<u128>,
647    Vec<i128>,
648    Vec<f64>,
649    String,
650    bool,
651    Vec<PropertyShared>,
652    Principal,
653    Option<Box<CandyShared>>,
654    Vec<u8>,
655    Vec<CandyShared>,
656    &str,
657    HashMap<CandyShared, CandyShared>,
658    HashSet<CandyShared>
659);
660
661/**
662 * `ToBlob` is a trait that is implemented by types that can be converted to a `Vec<u8>` blob.
663 *
664 * The `to_blob` method defined in this trait is used to perform the conversion to the `Vec<u8>` blob.
665 *
666 * # Examples
667 *
668 * ```
669 * use crate::candy::value::{CandyShared, ToBlob, ToCandyValue};
670 *
671 * let value = 42_u128.to_candy();
672 * let result = value.to_blob();
673 * assert_eq!(result, vec![42]);
674 * ```
675 */
676pub trait ToBlob {
677    fn to_blob(self) -> Vec<u8>;
678}
679
680impl ToBlob for BigUint {
681    #[inline]
682    fn to_blob(self) -> Vec<u8> {
683        let mut b = self;
684        let mut bytes: Vec<u8> = Vec::new();
685        loop {
686            let a = (b.clone() % BigUint::from(256_u32))
687                .to_u8()
688                .unwrap_or_else(|| ic_cdk::trap("Can not convert BigUint to u8"));
689            b /= BigUint::from(256_u32);
690            bytes.push(a);
691            if b == BigUint::from(0_u32) {
692                break;
693            }
694        }
695        bytes.reverse();
696        bytes
697    }
698}
699
700impl ToBlob for BigInt {
701    #[inline]
702    fn to_blob(self) -> Vec<u8> {
703        let c = u8::from(self < BigInt::from(0_i32));
704        let mut b = self.abs();
705        let mut bytes: Vec<u8> = vec![];
706        loop {
707            let a = (b.clone() % BigInt::from(128_i32))
708                .to_u8()
709                .unwrap_or_else(|| ic_cdk::trap("Can not convert BigInt to u8"));
710            b /= BigInt::from(128_i32);
711            bytes.push(a);
712            if b == BigInt::from(0_i32) {
713                break;
714            }
715        }
716        bytes.reverse();
717        bytes.insert(0, c);
718        bytes
719    }
720}
721
722impl ToBlob for char {
723    #[inline]
724    fn to_blob(self) -> Vec<u8> {
725        (self as u32).to_be_bytes().to_vec()
726    }
727}
728
729impl Hash for CandyShared {
730    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
731        match self {
732            CandyShared::Int(i) => i.hash(state),
733            CandyShared::Int8(i) => i.hash(state),
734            CandyShared::Int16(i) => i.hash(state),
735            CandyShared::Int32(i) => i.hash(state),
736            CandyShared::Int64(i) => i.hash(state),
737            CandyShared::Nat(i) => i.hash(state),
738            CandyShared::Nat8(i) => i.hash(state),
739            CandyShared::Nat16(i) => i.hash(state),
740            CandyShared::Nat32(i) => i.hash(state),
741            CandyShared::Nat64(i) => i.hash(state),
742            CandyShared::Float(i) => i.to_string().hash(state),
743            CandyShared::Text(i) => i.hash(state),
744            CandyShared::Bool(i) => i.hash(state),
745            CandyShared::Blob(i) => i.hash(state),
746            CandyShared::Bytes(i) => i.hash(state),
747            CandyShared::Class(i) => {
748                for prop in i {
749                    prop.name.hash(state);
750                    prop.value.hash(state);
751                    prop.immutable.hash(state);
752                }
753            }
754            CandyShared::Principal(i) => i.hash(state),
755            CandyShared::Option(i) => i.hash(state),
756            CandyShared::Array(i) => {
757                for prop in i {
758                    prop.hash(state)
759                }
760            }
761            CandyShared::Nats(i) => i.hash(state),
762            CandyShared::Ints(i) => i.hash(state),
763            CandyShared::Floats(i) => {
764                let mut buffer: Vec<u8> = Vec::new();
765                for num in i {
766                    buffer.append(num.to_string().into_bytes().as_mut());
767                }
768                buffer.hash(state)
769            }
770            CandyShared::Map(i) => {
771                for (key, value) in i {
772                    key.hash(state);
773                    value.hash(state);
774                }
775            }
776            CandyShared::Set(i) => {
777                for prop in i {
778                    prop.hash(state)
779                }
780            }
781        }
782    }
783}
784
785impl PartialEq for CandyShared {
786    fn eq(&self, other: &Self) -> bool {
787        match (self, other) {
788            (CandyShared::Int(i1), CandyShared::Int(i2)) => i1 == i2,
789            (CandyShared::Int8(i1), CandyShared::Int8(i2)) => i1 == i2,
790            (CandyShared::Int16(i1), CandyShared::Int16(i2)) => i1 == i2,
791            (CandyShared::Int32(i1), CandyShared::Int32(i2)) => i1 == i2,
792            (CandyShared::Int64(i1), CandyShared::Int64(i2)) => i1 == i2,
793            (CandyShared::Nat(i1), CandyShared::Nat(i2)) => i1 == i2,
794            (CandyShared::Nat8(i1), CandyShared::Nat8(i2)) => i1 == i2,
795            (CandyShared::Nat16(i1), CandyShared::Nat16(i2)) => i1 == i2,
796            (CandyShared::Nat32(i1), CandyShared::Nat32(i2)) => i1 == i2,
797            (CandyShared::Nat64(i1), CandyShared::Nat64(i2)) => i1 == i2,
798            (CandyShared::Float(i1), CandyShared::Float(i2)) => i1 == i2,
799            (CandyShared::Text(i1), CandyShared::Text(i2)) => i1 == i2,
800            (CandyShared::Bool(i1), CandyShared::Bool(i2)) => i1 == i2,
801            (CandyShared::Blob(i1), CandyShared::Blob(i2)) => i1 == i2,
802            (CandyShared::Bytes(i1), CandyShared::Bytes(i2)) => i1 == i2,
803            (CandyShared::Class(i1), CandyShared::Class(i2)) => i1 == i2,
804            (CandyShared::Principal(i1), CandyShared::Principal(i2)) => i1 == i2,
805            (CandyShared::Option(i1), CandyShared::Option(i2)) => i1 == i2,
806            (CandyShared::Array(i1), CandyShared::Array(i2)) => i1 == i2,
807            (CandyShared::Nats(i1), CandyShared::Nats(i2)) => i1 == i2,
808            (CandyShared::Ints(i1), CandyShared::Ints(i2)) => i1 == i2,
809            (CandyShared::Floats(i1), CandyShared::Floats(i2)) => i1 == i2,
810            (CandyShared::Map(map1), CandyShared::Map(map2)) => {
811                if map1.len() != map2.len() {
812                    false
813                } else {
814                    for (key1, value1) in map1.iter() {
815                        match map2.get(key1) {
816                            Some(value2) => {
817                                if !(value1 == value2) {
818                                    return false;
819                                }
820                            }
821                            None => return false,
822                        }
823                    }
824                    true
825                }
826            }
827            (CandyShared::Set(set1), CandyShared::Set(set2)) => {
828                if set1.len() != set2.len() {
829                    false
830                } else {
831                    for element in set1 {
832                        if !set2.contains(element) {
833                            return false;
834                        }
835                    }
836                    true
837                }
838            }
839            _ => false,
840        }
841    }
842}
843
844impl Eq for CandyShared {}
845
846impl Display for CandyShared {
847    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
848        match self {
849            Self::Int(val) => write!(f, "{}", val.0),
850            Self::Int8(val) => write!(f, "{}", val),
851            Self::Int16(val) => write!(f, "{}", val),
852            Self::Int32(val) => write!(f, "{}", val),
853            Self::Int64(val) => write!(f, "{}", val),
854            Self::Nat(val) => write!(f, "{}", val.0),
855            Self::Nat8(val) => write!(f, "{}", val),
856            Self::Nat16(val) => write!(f, "{}", val),
857            Self::Nat32(val) => write!(f, "{}", val),
858            Self::Nat64(val) => write!(f, "{}", val),
859            Self::Float(val) => write!(f, "{}", val),
860            Self::Text(val) => write!(f, "{}", val),
861            Self::Bool(val) => write!(f, "{}", val),
862            Self::Blob(val) => write!(f, "{}", val.encode_hex::<String>()),
863            Self::Bytes(val) => {
864                write!(f, "{}", val.encode_hex::<String>())
865            }
866            Self::Class(val) => write!(f, "{}", PropertyShared::stringify_properties(val)),
867            Self::Principal(val) => write!(f, "{}", val),
868            Self::Option(val) => write!(
869                f,
870                "{}",
871                val.as_ref()
872                    .map(|val| val.to_string())
873                    .unwrap_or_else(|| "null".to_string())
874            ),
875            Self::Array(val) => write!(f, "{}", {
876                let mut ret = String::new();
877                ret.push('[');
878                ret.push_str(
879                    val.iter()
880                        .map(|val| format!("{{{}}}", val))
881                        .collect::<Vec<String>>()
882                        .join(" ")
883                        .as_str(),
884                );
885                let _ = ret.trim_end();
886                ret.push(']');
887
888                ret
889            }),
890            Self::Nats(val) => write!(f, "{}", {
891                let mut ret = String::new();
892                ret.push('[');
893                ret.push_str(
894                    val.iter()
895                        .map(|val| val.to_string())
896                        .collect::<Vec<String>>()
897                        .join(" ")
898                        .as_str(),
899                );
900                let _ = ret.trim_end();
901                ret.push(']');
902                ret
903            }),
904            Self::Ints(val) => write!(f, "{}", {
905                let mut ret = String::new();
906                ret.push('[');
907                ret.push_str(
908                    val.iter()
909                        .map(|val| val.to_string())
910                        .collect::<Vec<String>>()
911                        .join(" ")
912                        .as_str(),
913                );
914                let _ = ret.trim_end();
915                ret.push(']');
916                ret
917            }),
918            Self::Floats(val) => write!(f, "{}", {
919                let mut ret = String::new();
920                ret.push('[');
921                ret.push_str(
922                    val.iter()
923                        .map(|val| val.to_string())
924                        .collect::<Vec<String>>()
925                        .join(" ")
926                        .as_str(),
927                );
928                let _ = ret.trim_end();
929                ret.push(']');
930
931                ret
932            }),
933            Self::Map(val) => write!(f, "{:?}", val),
934            Self::Set(val) => write!(f, "{:?}", val),
935        }
936    }
937}