postchain_client/utils/
operation.rs

1//! Operation parameter handling and data type conversion utilities.
2//! 
3//! This module provides functionality for handling operation parameters,
4//! data type conversions, and serialization/deserialization of various
5//! data types used in blockchain operations.
6//! 
7//! # Features
8//! - Generic parameter type system supporting various data types
9//! - Conversion between Rust structs and operation parameters
10//! - Serialization/deserialization support for complex data types
11//! - Support for large integers and binary data
12//! 
13//! # Example
14//! ```
15//! use std::collections::BTreeMap;
16//! use crate::utils::operation::{Operation, Params};
17//! 
18//! // Create operation parameters
19//! let params = vec![
20//!     ("key", Params::Text("value".to_string())),
21//!     ("number", Params::Integer(42))
22//! ];
23//! 
24//! // Create an operation
25//! let operation = Operation::from_dict("my_operation", params);
26//! ```
27
28extern crate num_bigint;
29
30use std::{collections::BTreeMap, fmt::Debug};
31use num_bigint::BigInt;
32use bigdecimal::BigDecimal;
33use std::str::FromStr;
34use base64::{Engine as _, engine::general_purpose};
35
36#[allow(unused_imports)]
37use postchain_client_derive::StructMetadata;
38
39pub trait StructMetadata {
40    fn field_names_and_types() -> std::collections::BTreeMap<String, String>;
41}
42
43/// Represents different types of operation parameters.
44/// 
45/// This enum provides a type-safe way to handle various data types
46/// used in blockchain operations, including primitive types, collections,
47/// and special types like BigInteger.
48#[derive(Clone, Debug, PartialEq)]
49pub enum Params {
50    /// Represents a null value
51    Null,
52    /// Represents a boolean value (true/false)
53    Boolean(bool),
54    /// Represents a 64-bit signed integer
55    Integer(i64),
56    /// Represents an arbitrary-precision integer using BigInt
57    BigInteger(BigInt),
58    /// Represents an arbitrary-precision decimal using BigDecimal
59    Decimal(BigDecimal),
60    /// Represents a UTF-8 encoded string
61    Text(String),
62    /// Represents a raw byte array
63    ByteArray(Vec<u8>),
64    /// Represents an ordered collection of Params
65    Array(Vec<Params>),
66    /// Represents a key-value mapping where keys are strings
67    Dict(BTreeMap<String, Params>)
68}
69
70pub type QueryParams = Params;
71pub type OperationParams = Params;
72
73/// Deserializes a string into a BigInt.
74/// 
75/// This function is used with serde to deserialize string-encoded
76/// big integers into BigInt type.
77/// 
78/// # Arguments
79/// * `deserializer` - The deserializer to use
80/// 
81/// # Returns
82/// Result containing either the deserialized BigInt or an error
83#[allow(dead_code)]
84fn deserialize_bigint<'de, D>(deserializer: D) -> Result<BigInt, D::Error>
85where
86    D: serde::Deserializer<'de>,
87{
88    let de_str: String = serde::Deserialize::deserialize(deserializer)?;
89    
90    BigInt::parse_bytes(de_str.as_bytes(), 10)
91        .ok_or(serde::de::Error::custom("Failed to parse BigInt"))
92}
93
94/// Deserializes a base64 string into a byte array.
95/// 
96/// This function is used with serde to deserialize base64-encoded
97/// strings into byte arrays.
98/// 
99/// # Arguments
100/// * `deserializer` - The deserializer to use
101/// 
102/// # Returns
103/// Result containing either the deserialized byte array or an error
104#[allow(dead_code)]
105fn deserialize_byte_array<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
106where
107    D: serde::Deserializer<'de>,
108{
109    let base64_str: String = serde::Deserialize::deserialize(deserializer)?;
110    general_purpose::STANDARD.decode(&base64_str).map_err(serde::de::Error::custom)
111}
112
113
114/// Serializes a BigInt into a string.
115/// 
116/// This function is used with serde to serialize BigInt values
117/// into string format.
118/// 
119/// # Arguments
120/// * `bigint` - The BigInt to serialize
121/// * `serializer` - The serializer to use
122/// 
123/// # Returns
124/// Result containing either the serialized string or an error
125#[allow(dead_code)]
126fn serialize_bigint<S>(bigint: &BigInt, serializer: S) -> Result<S::Ok, S::Error>
127where
128    S: serde::Serializer,
129{
130    let bigint_str = bigint.to_string();
131    serializer.serialize_str(&bigint_str)
132}
133
134/// Custom serialization for `BigDecimal`.
135///
136/// This function converts a `BigDecimal` value into a string representation,
137/// which is then serialized using the provided serializer.
138///
139/// # Arguments
140/// * `bigdecimal` - A reference to the `BigDecimal` value to serialize.
141/// * `serializer` - The serializer to use for converting the `BigDecimal` into a string.
142///
143/// # Returns
144/// Returns the serialized string representation of the `BigDecimal` if successful,
145/// or an error if serialization fails.
146///
147/// # Example
148/// ```
149/// #[derive(Debug, serde::Serialize)]
150/// struct MyStruct {
151///     #[serde(serialize_with = "serialize_bigdecimal")]
152///     value: BigDecimal,
153/// }
154///
155/// let my_struct = MyStruct { value: BigDecimal::from_str("3.14").unwrap() };
156/// let json = serde_json::to_string(&my_struct).unwrap();
157///
158#[allow(dead_code)]
159fn serialize_bigdecimal<S>(bigdecimal: &BigDecimal, serializer: S) -> Result<S::Ok, S::Error>
160where
161    S: serde::Serializer,
162{
163    serializer.serialize_str(&bigdecimal.to_string())
164}
165
166/// Custom deserialization for `BigDecimal`.
167///
168/// This function takes a string representation of a `BigDecimal` and converts it
169/// back into a `BigDecimal` value.
170///
171/// # Arguments
172/// * `deserializer` - The deserializer to use for converting the string into a `BigDecimal`.
173///
174/// # Returns
175/// Returns the deserialized `BigDecimal` if successful, or an error if deserialization fails.
176///
177/// # Example
178/// ```
179/// #[derive(Debug, serde::Deserialize)]
180/// struct MyStruct {
181///     #[serde(deserialize_with = "deserialize_bigdecimal")]
182///     value: BigDecimal,
183/// }
184///
185/// let json = r#"{"value": "3.14"}"#;
186/// let my_struct: MyStruct = serde_json::from_str(json).unwrap();
187/// ```
188#[allow(dead_code)]
189fn deserialize_bigdecimal<'de, D>(deserializer: D) -> Result<BigDecimal, D::Error>
190where
191    D: serde::Deserializer<'de>,
192{
193    let s: String = serde::Deserialize::deserialize(deserializer)?;
194    BigDecimal::from_str(&s)
195        .map_err(serde::de::Error::custom)
196}
197
198/// Represents a blockchain operation with parameters.
199/// 
200/// An operation can contain either a dictionary of named parameters
201/// or a list of unnamed parameters, along with an operation name.
202#[derive(Clone, Debug, PartialEq)]
203pub struct Operation<'a> {
204    /// Dictionary of named parameters
205    /// List of unnamed parameters
206    /// Name of the operation
207    pub dict: Option<Vec<(&'a str, Params)>>,
208    pub list: Option<Vec<Params>>,
209    pub operation_name: Option<&'a str>,
210}
211
212impl<'a> Default for Operation<'a> {
213    fn default() -> Self {
214        Self {
215            dict: None,
216            list: None,
217            operation_name: None,
218        }
219    }
220}
221
222/// Checks if a vector of JSON values represents a byte array.
223/// 
224/// # Arguments
225/// * `value` - Vector of JSON values to check
226/// 
227/// # Returns
228/// true if all values are valid u8 numbers
229fn is_vec_u8(value: &Vec<serde_json::Value>) -> bool {
230    value.iter().all(|v| {
231            if let serde_json::Value::Number(n) = v {
232                n.is_u64() && n.as_u64().unwrap() <= u8::MAX as u64
233            } else {
234                false
235            }
236        })    
237}
238
239impl<'a> Operation<'a> {
240    /// Creates a new Operation from a dictionary of parameters.
241    /// 
242    /// # Arguments
243    /// * `operation_name` - Name of the operation
244    /// * `params` - Vector of key-value parameter pairs
245    /// 
246    /// # Returns
247    /// A new Operation instance with dictionary parameters
248    pub fn from_dict(operation_name: &'a str, params: Vec<(&'a str, Params)>) -> Self {
249        Self {
250            dict: Some(params),
251            operation_name: Some(operation_name),
252            ..Default::default()
253        }
254    }
255
256    /// Creates a new Operation from a list of parameters.
257    /// 
258    /// # Arguments
259    /// * `operation_name` - Name of the operation
260    /// * `params` - Vector of parameters
261    /// 
262    /// # Returns
263    /// A new Operation instance with list parameters
264    pub fn from_list(operation_name: &'a str, params: Vec<Params>) -> Self {
265        Self {
266            list: Some(params),
267            operation_name: Some(operation_name),
268            ..Default::default()
269        }
270    }
271}
272
273impl Params {
274    /// Converts a boxed f64 value to its string representation.
275    /// 
276    /// # Arguments
277    /// * `val` - Boxed f64 value to convert
278    /// 
279    /// # Returns
280    /// String representation of the decimal value
281    pub fn decimal_to_string(val: Box<f64>) -> String {
282        val.to_string()
283    }
284
285    /// Converts a dictionary parameter to an array of its values.
286    /// 
287    /// # Arguments
288    /// * `self` - Dictionary parameter to convert
289    /// 
290    /// # Returns
291    /// Vector containing the values from the dictionary
292    /// 
293    /// # Panics
294    /// Panics if self is not a Params::Dict
295    pub fn dict_to_array(self) -> Vec<Params> {
296        match self {
297            Params::Dict(dict) => {
298                let values: Vec<Params> = dict.into_iter()
299                    .filter_map(|(_, value)| {
300                        Some(value)
301                    })
302                    .collect();
303                values
304            },
305            _ => panic!("Expected Params::Dict, found {:?}", self),
306        }
307    }
308
309    /// Checks if the parameter value is empty.
310    /// 
311    /// Works with Array, Dict, ByteArray, and Text parameter types.
312    /// 
313    /// # Returns
314    /// true if the parameter value is empty
315    /// 
316    /// # Panics
317    /// Panics if called on parameter types that don't support emptiness check
318    pub fn is_empty(self) -> bool {
319        match self {
320            Params::Array(array) => array.is_empty(),
321            Params::Dict(dict) => dict.is_empty(),
322            Params::ByteArray(bytearray) => bytearray.is_empty(),
323            Params::Text(text) => text.is_empty(),
324            _ => panic!("Cannot check empty of this type {:?}", self)
325        }
326    }
327
328    /// Returns the length of the parameter value.
329    /// 
330    /// Works with Array, Dict, ByteArray, and Text parameter types.
331    /// 
332    /// # Returns
333    /// Length of the parameter value
334    /// 
335    /// # Panics
336    /// Panics if called on parameter types that don't support length
337    pub fn len(self) -> usize {
338        match self {
339            Params::Array(array) => array.len(),
340            Params::Dict(dict) => dict.len(),
341            Params::ByteArray(bytearray) => bytearray.len(),
342            Params::Text(text) => text.len(),
343            _ => panic!("Cannot get length of this type {:?}", self)
344        }
345    }
346
347    /// Converts a dictionary parameter to a Rust struct.
348    /// 
349    /// # Type Parameters
350    /// * `T` - The target struct type that implements Default + Debug + Deserialize
351    /// 
352    /// # Returns
353    /// Result containing either the converted struct or an error message
354    /// 
355    /// # Example
356    /// ```
357    /// #[derive(Debug, Default, serde::Deserialize)]
358    /// struct MyStruct {
359    ///     field: String,
360    ///     value: i64,
361    /// }
362    /// 
363    /// let dict = Params::Dict(/* ... */);
364    /// let result: Result<MyStruct, String> = dict.to_struct();
365    /// ```
366    pub fn to_struct<T>(&self) -> Result<T, String>
367    where
368        T: Default + std::fmt::Debug + for<'de> serde::Deserialize<'de>,
369    {
370        match self {
371            Params::Dict(_) => {
372                let json_value = self.to_json_value();
373                
374                serde_json::from_value(json_value)
375                    .map_err(|e| format!("Failed to convert Params to struct: {}", e))
376            },
377            _ => Err(format!("Expected Params::Dict, found {:?}", self)),
378        }
379    }
380
381    /// Converts the parameter to a serde_json::Value.
382    /// 
383    /// This method handles all parameter types, including complex types
384    /// like BigInteger and ByteArray.
385    /// 
386    /// # Returns
387    /// JSON representation of the parameter
388    pub fn to_json_value(&self) -> serde_json::Value {
389        match *self {
390            Params::Null => serde_json::Value::Null,
391            Params::Boolean(b) => serde_json::Value::Bool(b),
392            Params::Integer(i) => serde_json::Value::Number(serde_json::Number::from(i)),
393            Params::BigInteger(ref big_int) => serde_json::Value::String(big_int.to_string()),
394            Params::Decimal(ref big_decimal) => serde_json::Value::String(big_decimal.to_string()),
395            Params::Text(ref text) => serde_json::Value::String(text.to_string()),
396            Params::ByteArray(ref bytearray) => {
397                if bytearray.len() == 33 {
398                    serde_json::Value::String(hex::encode(bytearray))
399                } else {
400                    let base64_encoded = general_purpose::STANDARD.encode(bytearray);
401                    serde_json::Value::String(base64_encoded)
402                }
403            },
404            Params::Array(ref array) => {
405                let json_array: Vec<serde_json::Value> = array.iter().map(|param| param.to_json_value()).collect();
406                serde_json::Value::Array(json_array)
407            },
408            Params::Dict(ref dict) => {
409                let json_object: serde_json::Map<String, serde_json::Value> = dict.iter()
410                    .map(|(key, value)| (key.to_string(), value.to_json_value()))
411                    .collect();
412                serde_json::Value::Object(json_object)
413            },
414        }
415    }
416
417    /// Creates a parameter from a Rust struct.
418    /// 
419    /// # Type Parameters
420    /// * `T` - The source struct type that implements Debug + Serialize
421    /// 
422    /// # Arguments
423    /// * `struct_instance` - Reference to the struct to convert
424    /// 
425    /// # Returns
426    /// Dictionary parameter containing the struct's fields
427    /// 
428    /// # Example
429    /// ```
430    /// #[derive(Debug, serde::Serialize)]
431    /// struct MyStruct {
432    ///     field: String,
433    ///     value: i64,
434    /// }
435    /// 
436    /// let my_struct = MyStruct { field: "test".into(), value: 42 };
437    /// let params = Params::from_struct(&my_struct);
438    /// ```
439    pub fn from_struct<T>(struct_instance: &T) -> Params
440    where
441        T: std::fmt::Debug + serde::Serialize + StructMetadata,
442    {
443        let json_value = serde_json::to_value(struct_instance)
444            .expect("Failed to convert struct to JSON value");
445
446        let fnat = T::field_names_and_types();
447
448        Params::Dict(Self::json_value_to_params_dict(json_value, fnat))
449    }
450
451    /// Converts a JSON value to a parameter dictionary, utilizing a provided function name to argument type (fnat) mapping.
452    ///
453    /// # Parameters
454    /// * `value`: The JSON value to be converted.
455    /// * `fnat`: A mapping of function names to argument types, used to determine the type of each parameter.
456    ///
457    /// # Returns
458    /// A `BTreeMap` containing the converted parameters, where each key is a parameter name and each value is a `Params` object.
459    ///
460    /// # Notes
461    /// * This function assumes that the input JSON value is an object, and will only process key-value pairs within that object.
462    /// * The `fnat` mapping is used to determine the type of each parameter, and should contain a mapping of function names to argument types.
463    /// * If a key in the input JSON value is not present in the `fnat` mapping, the function will use a default type for that parameter.
464    fn json_value_to_params_dict(value: serde_json::Value, fnat: BTreeMap<String, String>) -> BTreeMap<String, Params> {
465        let mut dict: BTreeMap<String, Params> = BTreeMap::new();
466
467        if let serde_json::Value::Object(map) = value {
468            for (key, val) in map {
469                let f_type = fnat.get(&key).cloned();
470                dict.insert(key, Self::value_to_params(val, f_type));
471            }
472        }
473
474        dict
475    }
476
477    /// Creates a list of parameters from a Rust struct.
478    /// 
479    /// Similar to from_struct, but returns a vector of values
480    /// instead of a dictionary.
481    /// 
482    /// # Type Parameters
483    /// * `T` - The source struct type that implements Debug + Serialize
484    /// 
485    /// # Arguments
486    /// * `struct_instance` - Reference to the struct to convert
487    /// 
488    /// # Returns
489    /// Vector of parameters containing the struct's field values
490    pub fn from_struct_to_list<T>(struct_instance: &T) -> Vec<Params>
491    where
492        T: std::fmt::Debug + serde::Serialize + StructMetadata,
493    {
494        let json_value = serde_json::to_value(struct_instance)
495            .expect("Failed to convert struct to JSON value");
496
497        let mut vec = Vec::new();
498
499        let fnat = T::field_names_and_types();
500
501        if let serde_json::Value::Object(map) = json_value {
502            for (key, val) in map {
503                let f_type = fnat.get(&key).cloned();
504                vec.push(Self::value_to_params(val, f_type));
505            }
506        }
507
508        vec
509    }
510
511    /// Converts a struct into a Vec<(String, Params)>.
512    /// 
513    /// # Type Parameters
514    /// * `T` - The struct type that implements Debug + Serialize
515    /// 
516    /// # Arguments
517    /// * `struct_instance` - Reference to the struct to convert
518    /// 
519    /// # Returns
520    /// Vector of tuples containing string keys and Params values
521    pub fn from_struct_to_vec<T>(struct_instance: &T) -> Vec<(String, Params)>
522    where
523        T: std::fmt::Debug + serde::Serialize,
524    {
525        let json_value = serde_json::to_value(struct_instance)
526            .expect("Failed to convert struct to JSON value");
527
528        let mut vec = Vec::new();
529
530        if let serde_json::Value::Object(map) = json_value {
531            for (key, val) in map {
532                vec.push((key, Self::value_to_params(val, None)));
533            }
534        }
535
536        vec
537    }
538
539    /// Converts a JSON value to a parameter.
540    ///
541    /// This function handles the conversion of various JSON types to their corresponding parameter types.
542    ///
543    /// ### Arguments
544    ///
545    /// * `value`: The JSON value to convert.
546    /// * `field_type`: An optional string indicating the type of the field. This is used to determine the type of the converted parameter.
547    ///
548    /// ### Returns
549    ///
550    /// The converted parameter.
551    ///
552    /// ### Notes
553    ///
554    /// * If the `field_type` is `Some` and contains "BigInt", the function will attempt to parse the JSON string value as a BigInteger.
555    /// * If the `field_type` is `Some` and contains "BigDecimal", the function will attempt to parse the JSON string value as a BigDecimal.
556    /// * If the JSON value is an array and all elements are numbers, the function will attempt to convert it to a byte array.
557    fn value_to_params(value: serde_json::Value, field_type: Option<String>) -> Params {
558        match value {
559            serde_json::Value::Null => Params::Null,
560            serde_json::Value::Bool(b) => Params::Boolean(b),
561            serde_json::Value::Number(n) => {
562                if let Some(i) = n.as_i64() {
563                    Params::Integer(i)
564                } else {
565                    Params::Null
566                }
567            },
568            serde_json::Value::String(s) => {
569                match field_type {
570                    Some(val) if val.contains("BigInt") => {
571                        match BigInt::parse_bytes(s.as_bytes(), 10) {
572                            Some(big_int) => Params::BigInteger(big_int),
573                            None => panic!("Required field is not a valid BigInteger"),
574                        }
575                    },
576                    Some(val) if val.contains("BigDecimal") => {
577                        match BigDecimal::parse_bytes(s.as_bytes(), 10) {
578                            Some(big_decimal) => Params::Decimal(big_decimal),
579                            None => panic!("Required field is not a valid BigDecimal"),
580                        }
581                    },
582                    _ => Params::Text(s)
583                }
584            },
585            serde_json::Value::Array(arr) => {
586                let is_vec_u8 = is_vec_u8(&arr);
587                if is_vec_u8 {
588                    let barr: Vec<u8> = arr.iter().map(|v|{v.as_u64().unwrap() as u8}).collect();
589                    return Params::ByteArray(barr)
590                }
591                let params_array: Vec<Params> = arr.into_iter().map(|x|{
592                    Self::value_to_params(x, None)
593                }).collect();
594                Params::Array(params_array)
595            },
596            serde_json::Value::Object(dict) => {
597                let params_dict: BTreeMap<String, Params> = dict.into_iter().map(|(k, v)| ( k, Self::value_to_params(v, None))).collect();
598                Params::Dict(params_dict)
599            }
600        }
601    }
602
603    /// Prints debug information about the parameter.
604    /// 
605    /// This method is only available in debug builds and provides
606    /// detailed information about the parameter's content.
607    /// 
608    /// # Arguments
609    /// * `self` - The parameter to debug print
610    #[cfg(debug_assertions)]
611    pub fn debug_print(&self) {
612        match self {
613            Params::Array(array) => {
614                    for item in array {
615                        item.debug_print();
616                    }
617            } 
618            Params::Dict(dict) => {
619                    for item in dict {
620                        eprintln!("key = {}", item.0);
621                        eprintln!("value = ");
622                        item.1.debug_print();
623                    }
624            }
625            Params::ByteArray(val) => {
626                eprintln!("{:?}", hex::encode(val));
627            }
628            _ =>
629                eprintln!("{:?}", self)
630        }
631    }
632}
633
634/// Converts `Params` to `bool`.
635///
636/// # Panics
637/// Panics if the `Params` variant is not `Params::Boolean`.
638impl From<Params> for bool {
639    fn from(value: Params) -> Self {
640        match value {
641            Params::Boolean(val) => val,
642            _ => panic!("Cannot convert {:?} to bool", value)
643        }
644    }
645}
646
647/// Converts `Params` to `i64`.
648///
649/// # Panics
650/// Panics if the `Params` variant is not `Params::Integer`.
651impl From<Params> for i64 {
652    fn from(value: Params) -> Self {
653        match value {
654            Params::Integer(val) => val,
655            _ => panic!("Cannot convert {:?} to i64", value)
656        }
657    }
658}
659
660/// Converts `Params` to `BigInt`.
661///
662/// # Panics
663/// Panics if the `Params` variant is not `Params::BigInteger`.
664impl From<Params> for BigInt {
665    fn from(value: Params) -> Self {
666        match value {
667            Params::BigInteger(val) => val,
668            _ => panic!("Cannot convert {:?} to BigInt", value)
669        }
670    }
671}
672
673/// Converts `Params` to `BigDecimal`.
674///
675/// # Panics
676/// Panics if the `Params` variant is not `Params::Decimal`.
677impl From<Params> for BigDecimal {
678    fn from(value: Params) -> Self {
679        match value {
680            Params::Decimal(val) => val,
681            _ => panic!("Cannot convert {:?} to BigDecimal", value)
682        }
683    }
684}
685
686/// Converts `Params` to `String`.
687///
688/// # Panics
689/// Panics if the `Params` variant is not `Params::Text`.
690impl From<Params> for String {
691    fn from(value: Params) -> Self {
692        match value {
693            Params::Text(val) => val,
694            _ => panic!("Cannot convert {:?} to String", value)
695        }
696    }
697}
698
699/// Converts `Params` to `Vec<u8>`.
700///
701/// # Panics
702/// Panics if the `Params` variant is not `Params::ByteArray`.
703impl From<Params> for Vec<u8> {
704    fn from(value: Params) -> Self {
705        match value {
706            Params::ByteArray(val) => val,
707            _ => panic!("Cannot convert {:?} to Vec<u8>", value)
708        }
709    }
710}
711
712/// Implements conversion from Params to `Vec<Params>`.
713/// 
714/// This implementation allows converting an Array parameter
715/// into a vector of parameters.
716/// 
717/// # Panics
718/// Panics if the parameter is not an Array type
719impl Into<Vec<Params>> for Params {
720    fn into(self) -> Vec<Params> {
721        match self {
722            Params::Array(array) => array,
723            _ => panic!("Cannot convert {:?} into Vec<Params>", self),
724        }
725    }
726}
727
728/// Implements conversion from Params to BTreeMap<String, Params>.
729/// 
730/// This implementation allows converting a Dict parameter
731/// into a BTreeMap of string keys and parameter values.
732/// 
733/// # Panics
734/// Panics if the parameter is not a Dict type
735impl Into<BTreeMap<String, Params>> for Params {
736    fn into(self) -> BTreeMap<String, Params> {
737        match self {
738            Params::Dict(dict) => dict,
739            _ => panic!("Cannot convert {:?} into BTreeMap", self),
740        }
741    }
742}
743
744#[test]
745fn test_serialize_struct_to_param_dict() {
746    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)]
747    struct TestStruct2 {
748        foo: String
749    }
750
751    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
752    struct TestStruct1 {
753        foo: String,
754        bar: i64,
755        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
756        bigint: num_bigint::BigInt,
757        ok: bool,
758        nested_struct: TestStruct2,
759        #[serde(deserialize_with="deserialize_byte_array")]
760        bytearray: Vec<u8>,
761    }
762
763    let ts1 = TestStruct1 {
764        foo: "foo".to_string(), bar: 1, ok: true,
765        bigint: num_bigint::BigInt::from(170141183460469231731687303715884105727 as i128),
766        nested_struct: TestStruct2{foo: "bar".to_string()}, bytearray: vec![1, 2, 3, 4, 5]
767    };
768
769    let r: Params = Params::from_struct(&ts1);
770
771    let m: Result<TestStruct1, String> = r.to_struct();
772
773    assert_eq!(ts1, m.unwrap());
774    
775}
776
777#[test]
778fn test_deserialize_param_dict_to_struct() {
779    use std::str::FromStr;
780
781    /// We have two options here for deserialization big integer:
782    /// 1. Use `String` struct
783    /// 2. Use `num_bigint::BigInt` struct with serder custom function
784    /// name `deserialize_bigint`
785    #[derive(Debug, Default, serde::Deserialize, PartialEq)]
786    struct TestNestedStruct {
787        bigint_as_string: String,
788        #[serde(deserialize_with = "deserialize_bigint")]
789        bigint_as_num_bigint: num_bigint::BigInt
790    }
791
792    #[derive(Debug, Default, serde::Deserialize, PartialEq)]
793    struct TestStruct {
794        x: i64,
795        y: i64,
796        z: String,
797        l: bool,
798        n: BigDecimal,
799        m: String,
800        dict: TestNestedStruct,
801        array: Vec<serde_json::Value>,
802        t: Option<bool>
803    }
804
805    let bigint = num_bigint::BigInt::from(100000000000000000000000 as i128);
806    let bytearray_value = b"1234";
807    let bytearray_base64_encoded = general_purpose::STANDARD.encode(bytearray_value);
808
809    let ts = TestStruct{
810        t: None,
811        x: 1, y: 2, z: "foo".to_string(), dict: TestNestedStruct {
812            bigint_as_string: bigint.to_string(),
813            bigint_as_num_bigint: (100000000000000000000000 as i128).into()
814        }, l: true, n: BigDecimal::from_str("3.14").unwrap(), m: bytearray_base64_encoded, array: vec![
815            serde_json::Value::Number(serde_json::Number::from(1 as i64)),
816            serde_json::Value::String("foo".to_string()),
817            ]
818    };
819
820    let mut nested_params: BTreeMap<String, Params> = BTreeMap::new();
821    nested_params.insert("bigint_as_string".to_string(), Params::BigInteger(bigint.clone()));
822    nested_params.insert("bigint_as_num_bigint".to_string(), Params::BigInteger(bigint.clone()));
823
824    let mut params: BTreeMap<String, Params> = BTreeMap::new();
825    params.insert("t".to_string(), Params::Null);
826    params.insert("x".to_string(), Params::Integer(1));
827    params.insert("y".to_string(), Params::Integer(2));
828    params.insert("z".to_string(), Params::Text("foo".to_string()));
829    params.insert("dict".to_string(), Params::Dict(nested_params));
830    params.insert("l".to_string(), Params::Boolean(true));
831    params.insert("n".to_string(), Params::Decimal(BigDecimal::from_str("3.14").unwrap()));
832    params.insert("m".to_string(), Params::ByteArray(bytearray_value.to_vec()));
833    params.insert("array".to_string(), Params::Array(vec![Params::Integer(1), Params::Text("foo".to_string())]));
834
835    let params_dict = Params::Dict(params);
836    let result: Result<TestStruct, String> = params_dict.to_struct();
837
838    if let Ok(val) = result {
839        assert_eq!(ts, val);
840    } else {
841        panic!("Error deserializing params: {}", result.unwrap_err());
842    }
843}
844
845#[test]
846fn test_serialize_deserialize_bigint() {
847    let large_int_str = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
848    let large_int = BigInt::parse_bytes(large_int_str.as_bytes(), 10).unwrap();
849
850    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
851    struct TestStruct {
852        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
853        bigint1: num_bigint::BigInt,
854    }
855
856    let ts = TestStruct {
857        bigint1: large_int.clone(),
858    };
859
860    let mut params: BTreeMap<String, Params> = BTreeMap::new();
861    params.insert("bigint1".to_string(), Params::BigInteger(large_int));
862    
863    let result: Result<TestStruct, String> = Params::Dict(params).to_struct();
864
865    if let Ok(val) = result {
866        assert_eq!(ts, val);
867    } else {
868        panic!("Error deserializing params: {}", result.unwrap_err());
869    }
870}
871
872#[test]
873fn test_serialize_deserialize_bigdecimal() {
874    use std::str::FromStr;
875
876    let large_int_str = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
877    let large_int = BigInt::parse_bytes(large_int_str.as_bytes(), 10).unwrap();
878
879    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
880    struct TestStruct {
881        no_number: String,
882        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
883        bigint: BigInt,
884        #[serde(serialize_with = "serialize_bigdecimal", deserialize_with = "deserialize_bigdecimal")]
885        bigdecimal: BigDecimal
886    }
887
888    let ts = TestStruct {
889        no_number: "Hello!".to_string(),
890        bigdecimal: BigDecimal::from_str(".02").unwrap(),
891        bigint: large_int
892    };
893
894    let r: Params = Params::from_struct(&ts);
895
896    let m: Result<TestStruct, String> = r.to_struct();
897
898    assert_eq!(ts, m.unwrap());
899}
900
901#[test]
902fn test_struct_metadata_derive() {
903    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
904    struct TestStruct {
905        text: String,
906        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
907        bigint: BigInt,
908        #[serde(serialize_with = "serialize_bigdecimal", deserialize_with = "deserialize_bigdecimal")]
909        bigdecimal: BigDecimal
910    }
911
912    let ts = TestStruct {
913        text: "Hello!".to_string(),
914        bigdecimal: BigDecimal::parse_bytes("55.77e-5".as_bytes(), 10).unwrap(),
915        bigint: BigInt::parse_bytes("123".as_bytes(), 10).unwrap()
916    };
917
918    let r: Params = Params::from_struct(&ts);
919    let m = r.to_struct::<TestStruct>().unwrap();
920    
921    assert_eq!(m.bigdecimal, BigDecimal::parse_bytes("55.77e-5".as_bytes(), 10).unwrap());
922    assert_eq!(m.bigint, BigInt::parse_bytes("123".as_bytes(), 10).unwrap());
923}