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)]
203#[derive(Default)]
204pub struct Operation {
205    /// Dictionary of named parameters
206    /// List of unnamed parameters
207    /// Name of the operation
208    pub dict: Option<Vec<(String, Params)>>,
209    pub list: Option<Vec<Params>>,
210    pub operation_name: Option<String>,
211}
212
213
214/// Checks if a vector of JSON values represents a byte array.
215/// 
216/// # Arguments
217/// * `value` - Vector of JSON values to check
218/// 
219/// # Returns
220/// true if all values are valid u8 numbers
221fn is_vec_u8(value: &[serde_json::Value]) -> bool {
222    value.iter().all(|v| {
223            if let serde_json::Value::Number(n) = v {
224                n.is_u64() && n.as_u64().unwrap() <= u8::MAX as u64
225            } else {
226                false
227            }
228        })    
229}
230
231impl std::fmt::Display for Params {
232    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233        match self {
234            Params::Text(text) => write!(f, "{text}"),
235            Params::Integer(i) => write!(f, "Integer({i})"),
236            Params::ByteArray(bytes) => write!(f, "ByteArray({bytes:?})"),
237            Params::BigInteger(bi) => write!(f, "BigInteger({bi})"),
238            Params::Array(arr) => write!(f, "Array({arr:?})"),
239            Params::Null => write!(f, "Null"),
240            Params::Boolean(b) => write!(f, "Boolean({b})"),
241            Params::Decimal(bd) => write!(f, "Decimal({bd})"),
242            Params::Dict(dict) => {
243                let dict_str: Vec<String> = dict.iter()
244                    .map(|(k, v)| format!("{k}: {v}"))
245                    .collect();
246                write!(f, "Dict({})", dict_str.join(", "))
247            }
248        }
249    }
250}
251
252impl Operation {
253    /// Creates a new Operation from a dictionary of parameters.
254    /// 
255    /// # Arguments
256    /// * `operation_name` - Name of the operation
257    /// * `params` - Vector of key-value parameter pairs
258    /// 
259    /// # Returns
260    /// A new Operation instance with dictionary parameters
261    pub fn from_dict(operation_name: String, params: Vec<(String, Params)>) -> Self {
262        Self {
263            dict: Some(params),
264            operation_name: Some(operation_name),
265            ..Default::default()
266        }
267    }
268
269    /// Creates a new Operation from a list of parameters.
270    /// 
271    /// # Arguments
272    /// * `operation_name` - Name of the operation
273    /// * `params` - Vector of parameters
274    /// 
275    /// # Returns
276    /// A new Operation instance with list parameters
277    pub fn from_list(operation_name: String, params: Vec<Params>) -> Self {
278        Self {
279            list: Some(params),
280            operation_name: Some(operation_name),
281            ..Default::default()
282        }
283    }
284}
285
286impl Params {
287    /// Converts a boxed f64 value to its string representation.
288    /// 
289    /// # Arguments
290    /// * `val` - Boxed f64 value to convert
291    /// 
292    /// # Returns
293    /// String representation of the decimal value
294    pub fn decimal_to_string(val: Box<f64>) -> String {
295        val.to_string()
296    }
297
298    /// Converts a dictionary parameter into an array of alternating keys and values.
299    ///
300    /// # Returns
301    ///
302    /// A vector where each key from the dictionary is followed by its corresponding value as `Params`.
303    ///
304    /// # Panics
305    ///
306    /// Panics if called on a `Params` variant that is not `Dict`.
307    ///
308    /// # Example
309    /// ```
310    /// let dict = Params::Dict(BTreeMap::from([
311    ///     ("a".to_string(), Params::Integer(1)),
312    ///     ("b".to_string(), Params::Text("foo".to_string())),
313    /// ]));
314    /// let arr = dict.dict_to_array();
315    /// // arr = [Params::Text("a"), Params::Integer(1), Params::Text("b"), Params::Text("foo")]
316    /// ```
317    pub fn dict_to_array(self) -> Vec<Params> {
318        match self {
319            Params::Dict(dict) => {
320                let mut array_data = Vec::new();
321                for (key, value) in dict.into_iter() {
322                    array_data.push(Params::Text(key));
323                    array_data.push(value);
324                }
325                array_data
326            },
327            _ => panic!("Expected Params::Dict, found {self:?}"),
328        }
329    }
330
331    /// Converts a dictionary parameter to an array of its values.
332    ///
333    /// # Returns
334    ///
335    /// A vector containing only the values from the dictionary, in the order of their keys.
336    ///
337    /// # Panics
338    ///
339    /// Panics if called on a `Params` variant that is not `Dict`.
340    ///
341    /// # Example
342    /// ```
343    /// let dict = Params::Dict(BTreeMap::from([
344    ///     ("a".to_string(), Params::Integer(1)),
345    ///     ("b".to_string(), Params::Text("foo".to_string())),
346    /// ]));
347    /// let arr = dict.dict_to_array_values();
348    /// // arr = [Params::Integer(1), Params::Text("foo")]
349    /// ```
350    pub fn dict_to_array_values(self) -> Vec<Params> {
351        match self {
352            Params::Dict(dict) => {
353                let values: Vec<Params> = dict.into_values().collect();
354                values
355            },
356            _ => panic!("Expected Params::Dict, found {self:?}"),
357        }
358    }
359
360    /// Checks if the parameter value is empty.
361    /// 
362    /// Works with Array, Dict, ByteArray, and Text parameter types.
363    /// 
364    /// # Returns
365    /// true if the parameter value is empty
366    /// 
367    /// # Panics
368    /// Panics if called on parameter types that don't support emptiness check
369    pub fn is_empty(self) -> bool {
370        match self {
371            Params::Array(array) => array.is_empty(),
372            Params::Dict(dict) => dict.is_empty(),
373            Params::ByteArray(bytearray) => bytearray.is_empty(),
374            Params::Text(text) => text.is_empty(),
375            _ => panic!("Cannot check empty of this type {self:?}")
376        }
377    }
378
379    /// Returns the length of the parameter value.
380    /// 
381    /// Works with Array, Dict, ByteArray, and Text parameter types.
382    /// 
383    /// # Returns
384    /// Length of the parameter value
385    /// 
386    /// # Panics
387    /// Panics if called on parameter types that don't support length
388    pub fn len(self) -> usize {
389        match self {
390            Params::Array(array) => array.len(),
391            Params::Dict(dict) => dict.len(),
392            Params::ByteArray(bytearray) => bytearray.len(),
393            Params::Text(text) => text.len(),
394            _ => panic!("Cannot get length of this type {self:?}")
395        }
396    }
397
398    pub fn to_hex_encode(self) -> String {
399        match self {
400            Params::ByteArray(bytearray) => hex::encode(bytearray),
401            _ => panic!("Expected Params::ByteArray, found {self:?}"),
402        }
403    }
404
405    pub fn to_vec(self) -> Vec<u8> {
406        match self {
407            Params::ByteArray(bytearray) => bytearray,
408            _ => panic!("Expected Params::ByteArray, found {self:?}"),
409        }
410    }
411
412    // pub fn to_string(self) -> String {
413    //     match self {
414    //         Params::Text(text) => text,
415    //         _ => panic!("Expected Params::Text, found {self:?}"),
416    //     }
417    // }
418
419    /// Converts a dictionary parameter to a Rust struct.
420    /// 
421    /// # Type Parameters
422    /// * `T` - The target struct type that implements Default + Debug + Deserialize
423    /// 
424    /// # Returns
425    /// Result containing either the converted struct or an error message
426    /// 
427    /// # Example
428    /// ```
429    /// #[derive(Debug, Default, serde::Deserialize)]
430    /// struct MyStruct {
431    ///     field: String,
432    ///     value: i64,
433    /// }
434    /// 
435    /// let dict = Params::Dict(/* ... */);
436    /// let result: Result<MyStruct, String> = dict.to_struct();
437    /// ```
438    pub fn to_struct<T>(&self) -> Result<T, String>
439    where
440        T: Default + std::fmt::Debug + for<'de> serde::Deserialize<'de>,
441    {
442        match self {
443            Params::Dict(_) => {
444                let json_value = self.to_json_value();
445                
446                serde_json::from_value(json_value)
447                    .map_err(|e| format!("Failed to convert Params to struct: {e}"))
448            },
449            _ => Err(format!("Expected Params::Dict, found {self:?}")),
450        }
451    }
452
453    /// Converts the parameter to a serde_json::Value.
454    /// 
455    /// This method handles all parameter types, including complex types
456    /// like BigInteger and ByteArray.
457    /// 
458    /// # Returns
459    /// JSON representation of the parameter
460    pub fn to_json_value(&self) -> serde_json::Value {
461        match *self {
462            Params::Null => serde_json::Value::Null,
463            Params::Boolean(b) => serde_json::Value::Bool(b),
464            Params::Integer(i) => serde_json::Value::Number(serde_json::Number::from(i)),
465            Params::BigInteger(ref big_int) => serde_json::Value::String(big_int.to_string()),
466            Params::Decimal(ref big_decimal) => serde_json::Value::String(big_decimal.to_string()),
467            Params::Text(ref text) => serde_json::Value::String(text.to_string()),
468            Params::ByteArray(ref bytearray) => {
469                if bytearray.len() == 33 {
470                    serde_json::Value::String(hex::encode(bytearray))
471                } else {
472                    let base64_encoded = general_purpose::STANDARD.encode(bytearray);
473                    serde_json::Value::String(base64_encoded)
474                }
475            },
476            Params::Array(ref array) => {
477                let json_array: Vec<serde_json::Value> = array.iter().map(|param| param.to_json_value()).collect();
478                serde_json::Value::Array(json_array)
479            },
480            Params::Dict(ref dict) => {
481                let json_object: serde_json::Map<String, serde_json::Value> = dict.iter()
482                    .map(|(key, value)| (key.to_string(), value.to_json_value()))
483                    .collect();
484                serde_json::Value::Object(json_object)
485            },
486        }
487    }
488
489    /// Creates a parameter from a Rust struct.
490    /// 
491    /// # Type Parameters
492    /// * `T` - The source struct type that implements Debug + Serialize
493    /// 
494    /// # Arguments
495    /// * `struct_instance` - Reference to the struct to convert
496    /// 
497    /// # Returns
498    /// Dictionary parameter containing the struct's fields
499    /// 
500    /// # Example
501    /// ```
502    /// #[derive(Debug, serde::Serialize)]
503    /// struct MyStruct {
504    ///     field: String,
505    ///     value: i64,
506    /// }
507    /// 
508    /// let my_struct = MyStruct { field: "test".into(), value: 42 };
509    /// let params = Params::from_struct(&my_struct);
510    /// ```
511    pub fn from_struct<T>(struct_instance: &T) -> Params
512    where
513        T: std::fmt::Debug + serde::Serialize + StructMetadata,
514    {
515        let json_value = serde_json::to_value(struct_instance)
516            .expect("Failed to convert struct to JSON value");
517
518        let fnat = T::field_names_and_types();
519
520        Params::Dict(Self::json_value_to_params_dict(json_value, fnat))
521    }
522
523    /// Converts a JSON value to a parameter dictionary, utilizing a provided function name to argument type (fnat) mapping.
524    ///
525    /// # Parameters
526    /// * `value`: The JSON value to be converted.
527    /// * `fnat`: A mapping of function names to argument types, used to determine the type of each parameter.
528    ///
529    /// # Returns
530    /// A `BTreeMap` containing the converted parameters, where each key is a parameter name and each value is a `Params` object.
531    ///
532    /// # Notes
533    /// * This function assumes that the input JSON value is an object, and will only process key-value pairs within that object.
534    /// * The `fnat` mapping is used to determine the type of each parameter, and should contain a mapping of function names to argument types.
535    /// * 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.
536    fn json_value_to_params_dict(value: serde_json::Value, fnat: BTreeMap<String, String>) -> BTreeMap<String, Params> {
537        let mut dict: BTreeMap<String, Params> = BTreeMap::new();
538
539        if let serde_json::Value::Object(map) = value {
540            for (key, val) in map {
541                let f_type = fnat.get(&key).cloned();
542                dict.insert(key, Self::value_to_params(val, f_type));
543            }
544        }
545
546        dict
547    }
548
549    /// Creates a list of parameters from a Rust struct.
550    /// 
551    /// Similar to from_struct, but returns a vector of values
552    /// instead of a dictionary.
553    /// 
554    /// # Type Parameters
555    /// * `T` - The source struct type that implements Debug + Serialize
556    /// 
557    /// # Arguments
558    /// * `struct_instance` - Reference to the struct to convert
559    /// 
560    /// # Returns
561    /// Vector of parameters containing the struct's field values
562    pub fn from_struct_to_list<T>(struct_instance: &T) -> Vec<Params>
563    where
564        T: std::fmt::Debug + serde::Serialize + StructMetadata,
565    {
566        let json_value = serde_json::to_value(struct_instance)
567            .expect("Failed to convert struct to JSON value");
568
569        let mut vec = Vec::new();
570
571        let fnat = T::field_names_and_types();
572
573        if let serde_json::Value::Object(map) = json_value {
574            for (key, val) in map {
575                let f_type = fnat.get(&key).cloned();
576                vec.push(Self::value_to_params(val, f_type));
577            }
578        }
579
580        vec
581    }
582
583    /// Converts a struct into a Vec<(String, Params)>.
584    /// 
585    /// # Type Parameters
586    /// * `T` - The struct type that implements Debug + Serialize
587    /// 
588    /// # Arguments
589    /// * `struct_instance` - Reference to the struct to convert
590    /// 
591    /// # Returns
592    /// Vector of tuples containing string keys and Params values
593    pub fn from_struct_to_vec<T>(struct_instance: &T) -> Vec<(String, Params)>
594    where
595        T: std::fmt::Debug + serde::Serialize,
596    {
597        let json_value = serde_json::to_value(struct_instance)
598            .expect("Failed to convert struct to JSON value");
599
600        let mut vec = Vec::new();
601
602        if let serde_json::Value::Object(map) = json_value {
603            for (key, val) in map {
604                vec.push((key, Self::value_to_params(val, None)));
605            }
606        }
607
608        vec
609    }
610
611    /// Converts a JSON value to a parameter.
612    ///
613    /// This function handles the conversion of various JSON types to their corresponding parameter types.
614    ///
615    /// ### Arguments
616    ///
617    /// * `value`: The JSON value to convert.
618    /// * `field_type`: An optional string indicating the type of the field. This is used to determine the type of the converted parameter.
619    ///
620    /// ### Returns
621    ///
622    /// The converted parameter.
623    ///
624    /// ### Notes
625    ///
626    /// * If the `field_type` is `Some` and contains "BigInt", the function will attempt to parse the JSON string value as a BigInteger.
627    /// * If the `field_type` is `Some` and contains "BigDecimal", the function will attempt to parse the JSON string value as a BigDecimal.
628    /// * If the JSON value is an array and all elements are numbers, the function will attempt to convert it to a byte array.
629    fn value_to_params(value: serde_json::Value, field_type: Option<String>) -> Params {
630        match value {
631            serde_json::Value::Null => Params::Null,
632            serde_json::Value::Bool(b) => Params::Boolean(b),
633            serde_json::Value::Number(n) => {
634                if let Some(i) = n.as_i64() {
635                    Params::Integer(i)
636                } else {
637                    Params::Null
638                }
639            },
640            serde_json::Value::String(s) => {
641                match field_type {
642                    Some(val) if val.contains("BigInt") => {
643                        match BigInt::parse_bytes(s.as_bytes(), 10) {
644                            Some(big_int) => Params::BigInteger(big_int),
645                            None => panic!("Required field is not a valid BigInteger"),
646                        }
647                    },
648                    Some(val) if val.contains("BigDecimal") => {
649                        match BigDecimal::parse_bytes(s.as_bytes(), 10) {
650                            Some(big_decimal) => Params::Decimal(big_decimal),
651                            None => panic!("Required field is not a valid BigDecimal"),
652                        }
653                    },
654                    _ => Params::Text(s)
655                }
656            },
657            serde_json::Value::Array(arr) => {
658                let is_vec_u8 = is_vec_u8(&arr);
659                if is_vec_u8 {
660                    let barr: Vec<u8> = arr.iter().map(|v|{v.as_u64().unwrap() as u8}).collect();
661                    return Params::ByteArray(barr)
662                }
663                let params_array: Vec<Params> = arr.into_iter().map(|x|{
664                    Self::value_to_params(x, None)
665                }).collect();
666                Params::Array(params_array)
667            },
668            serde_json::Value::Object(dict) => {
669                let params_dict: BTreeMap<String, Params> = dict.into_iter().map(|(k, v)| ( k, Self::value_to_params(v, None))).collect();
670                Params::Dict(params_dict)
671            }
672        }
673    }
674
675    /// Prints debug information about the parameter.
676    /// 
677    /// This method is only available in debug builds and provides
678    /// detailed information about the parameter's content.
679    /// 
680    /// # Arguments
681    /// * `self` - The parameter to debug print
682    #[cfg(debug_assertions)]
683    pub fn debug_print(&self) {
684        match self {
685            Params::Array(array) => {
686                    for item in array {
687                        item.debug_print();
688                    }
689            } 
690            Params::Dict(dict) => {
691                    for item in dict {
692                        eprintln!("key = {}", item.0);
693                        eprintln!("value = ");
694                        item.1.debug_print();
695                    }
696            }
697            Params::ByteArray(val) => {
698                eprintln!("{:?}", hex::encode(val));
699            }
700            _ =>
701                eprintln!("{self:?}")
702        }
703    }
704}
705
706/// Converts `Params` to `bool`.
707///
708/// # Panics
709/// Panics if the `Params` variant is not `Params::Boolean`.
710impl From<Params> for bool {
711    fn from(value: Params) -> Self {
712        match value {
713            Params::Boolean(val) => val,
714            _ => panic!("Cannot convert {value:?} to bool")
715        }
716    }
717}
718
719/// Converts `Params` to `i64`.
720///
721/// # Panics
722/// Panics if the `Params` variant is not `Params::Integer`.
723impl From<Params> for i64 {
724    fn from(value: Params) -> Self {
725        match value {
726            Params::Integer(val) => val,
727            _ => panic!("Cannot convert {value:?} to i64")
728        }
729    }
730}
731
732/// Converts `Params` to `BigInt`.
733///
734/// # Panics
735/// Panics if the `Params` variant is not `Params::BigInteger`.
736impl From<Params> for BigInt {
737    fn from(value: Params) -> Self {
738        match value {
739            Params::BigInteger(val) => val,
740            _ => panic!("Cannot convert {value:?} to BigInt")
741        }
742    }
743}
744
745/// Converts `Params` to `BigDecimal`.
746///
747/// # Panics
748/// Panics if the `Params` variant is not `Params::Decimal`.
749impl From<Params> for BigDecimal {
750    fn from(value: Params) -> Self {
751        match value {
752            Params::Decimal(val) => val,
753            _ => panic!("Cannot convert {value:?} to BigDecimal")
754        }
755    }
756}
757
758/// Converts `Params` to `String`.
759///
760/// # Panics
761/// Panics if the `Params` variant is not `Params::Text`.
762impl From<Params> for String {
763    fn from(value: Params) -> Self {
764        match value {
765            Params::Text(val) => val,
766            _ => panic!("Cannot convert {value:?} to String")
767        }
768    }
769}
770
771/// Converts `Params` to `Vec<u8>`.
772///
773/// # Panics
774/// Panics if the `Params` variant is not `Params::ByteArray`.
775impl From<Params> for Vec<u8> {
776    fn from(value: Params) -> Self {
777        match value {
778            Params::ByteArray(val) => val,
779            _ => panic!("Cannot convert {value:?} to Vec<u8>")
780        }
781    }
782}
783
784/// Implements conversion from Params to `Vec<Params>`.
785/// 
786/// This implementation allows converting an Array parameter
787/// into a vector of parameters.
788/// 
789/// # Panics
790/// Panics if the parameter is not an Array type
791impl From<Params> for Vec<Params> {
792    fn from(val: Params) -> Self {
793        match val {
794            Params::Array(array) => array,
795            _ => panic!("Cannot convert {val:?} into Vec<Params>"),
796        }
797    }
798}
799
800/// Implements conversion from Params to BTreeMap<String, Params>.
801/// 
802/// This implementation allows converting a Dict parameter
803/// into a BTreeMap of string keys and parameter values.
804/// 
805/// # Panics
806/// Panics if the parameter is not a Dict type
807impl From<Params> for BTreeMap<String, Params> {
808    fn from(val: Params) -> Self {
809        match val {
810            Params::Dict(dict) => dict,
811            _ => panic!("Cannot convert {val:?} into BTreeMap"),
812        }
813    }
814}
815
816#[test]
817fn test_serialize_struct_to_param_dict() {
818    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq)]
819    struct TestStruct2 {
820        foo: String
821    }
822
823    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
824    struct TestStruct1 {
825        foo: String,
826        bar: i64,
827        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
828        bigint: num_bigint::BigInt,
829        ok: bool,
830        nested_struct: TestStruct2,
831        #[serde(deserialize_with="deserialize_byte_array")]
832        bytearray: Vec<u8>,
833    }
834
835    let ts1 = TestStruct1 {
836        foo: "foo".to_string(), bar: 1, ok: true,
837        bigint: num_bigint::BigInt::from(170141183460469231731687303715884105727_i128),
838        nested_struct: TestStruct2{foo: "bar".to_string()}, bytearray: vec![1, 2, 3, 4, 5]
839    };
840
841    let r: Params = Params::from_struct(&ts1);
842
843    let m: Result<TestStruct1, String> = r.to_struct();
844
845    assert_eq!(ts1, m.unwrap());
846    
847}
848
849#[test]
850fn test_deserialize_param_dict_to_struct() {
851    use std::str::FromStr;
852
853    /// We have two options here for deserialization big integer:
854    /// 1. Use `String` struct
855    /// 2. Use `num_bigint::BigInt` struct with serder custom function
856    ///    name `deserialize_bigint`
857    #[derive(Debug, Default, serde::Deserialize, PartialEq)]
858    struct TestNestedStruct {
859        bigint_as_string: String,
860        #[serde(deserialize_with = "deserialize_bigint")]
861        bigint_as_num_bigint: num_bigint::BigInt
862    }
863
864    #[derive(Debug, Default, serde::Deserialize, PartialEq)]
865    struct TestStruct {
866        x: i64,
867        y: i64,
868        z: String,
869        l: bool,
870        n: BigDecimal,
871        m: String,
872        dict: TestNestedStruct,
873        array: Vec<serde_json::Value>,
874        t: Option<bool>
875    }
876
877    let bigint = num_bigint::BigInt::from(100000000000000000000000_i128);
878    let bytearray_value = b"1234";
879    let bytearray_base64_encoded = general_purpose::STANDARD.encode(bytearray_value);
880
881    let ts = TestStruct{
882        t: None,
883        x: 1, y: 2, z: "foo".to_string(), dict: TestNestedStruct {
884            bigint_as_string: bigint.to_string(),
885            bigint_as_num_bigint: 100000000000000000000000_i128.into()
886        }, l: true, n: BigDecimal::from_str("3.14").unwrap(), m: bytearray_base64_encoded, array: vec![
887            serde_json::Value::Number(serde_json::Number::from(1_i64)),
888            serde_json::Value::String("foo".to_string()),
889            ]
890    };
891
892    let mut nested_params: BTreeMap<String, Params> = BTreeMap::new();
893    nested_params.insert("bigint_as_string".to_string(), Params::BigInteger(bigint.clone()));
894    nested_params.insert("bigint_as_num_bigint".to_string(), Params::BigInteger(bigint.clone()));
895
896    let mut params: BTreeMap<String, Params> = BTreeMap::new();
897    params.insert("t".to_string(), Params::Null);
898    params.insert("x".to_string(), Params::Integer(1));
899    params.insert("y".to_string(), Params::Integer(2));
900    params.insert("z".to_string(), Params::Text("foo".to_string()));
901    params.insert("dict".to_string(), Params::Dict(nested_params));
902    params.insert("l".to_string(), Params::Boolean(true));
903    params.insert("n".to_string(), Params::Decimal(BigDecimal::from_str("3.14").unwrap()));
904    params.insert("m".to_string(), Params::ByteArray(bytearray_value.to_vec()));
905    params.insert("array".to_string(), Params::Array(vec![Params::Integer(1), Params::Text("foo".to_string())]));
906
907    let params_dict = Params::Dict(params);
908    let result: Result<TestStruct, String> = params_dict.to_struct();
909
910    if let Ok(val) = result {
911        assert_eq!(ts, val);
912    } else {
913        panic!("Error deserializing params: {}", result.unwrap_err());
914    }
915}
916
917#[test]
918fn test_serialize_deserialize_bigint() {
919    let large_int_str = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
920    let large_int = BigInt::parse_bytes(large_int_str.as_bytes(), 10).unwrap();
921
922    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
923    struct TestStruct {
924        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
925        bigint1: num_bigint::BigInt,
926    }
927
928    let ts = TestStruct {
929        bigint1: large_int.clone(),
930    };
931
932    let mut params: BTreeMap<String, Params> = BTreeMap::new();
933    params.insert("bigint1".to_string(), Params::BigInteger(large_int));
934    
935    let result: Result<TestStruct, String> = Params::Dict(params).to_struct();
936
937    if let Ok(val) = result {
938        assert_eq!(ts, val);
939    } else {
940        panic!("Error deserializing params: {}", result.unwrap_err());
941    }
942}
943
944#[test]
945fn test_serialize_deserialize_bigdecimal() {
946    use std::str::FromStr;
947
948    let large_int_str = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
949    let large_int = BigInt::parse_bytes(large_int_str.as_bytes(), 10).unwrap();
950
951    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
952    struct TestStruct {
953        no_number: String,
954        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
955        bigint: BigInt,
956        #[serde(serialize_with = "serialize_bigdecimal", deserialize_with = "deserialize_bigdecimal")]
957        bigdecimal: BigDecimal
958    }
959
960    let ts = TestStruct {
961        no_number: "Hello!".to_string(),
962        bigdecimal: BigDecimal::from_str(".02").unwrap(),
963        bigint: large_int
964    };
965
966    let r: Params = Params::from_struct(&ts);
967
968    let m: Result<TestStruct, String> = r.to_struct();
969
970    assert_eq!(ts, m.unwrap());
971}
972
973#[test]
974fn test_struct_metadata_derive() {
975    #[derive(Debug, Default, serde::Serialize, serde::Deserialize, PartialEq, StructMetadata)]
976    struct TestStruct {
977        text: String,
978        #[serde(serialize_with = "serialize_bigint", deserialize_with = "deserialize_bigint")]
979        bigint: BigInt,
980        #[serde(serialize_with = "serialize_bigdecimal", deserialize_with = "deserialize_bigdecimal")]
981        bigdecimal: BigDecimal
982    }
983
984    let ts = TestStruct {
985        text: "Hello!".to_string(),
986        bigdecimal: BigDecimal::parse_bytes("55.77e-5".as_bytes(), 10).unwrap(),
987        bigint: BigInt::parse_bytes("123".as_bytes(), 10).unwrap()
988    };
989
990    let r: Params = Params::from_struct(&ts);
991    let m = r.to_struct::<TestStruct>().unwrap();
992    
993    assert_eq!(m.bigdecimal, BigDecimal::parse_bytes("55.77e-5".as_bytes(), 10).unwrap());
994    assert_eq!(m.bigint, BigInt::parse_bytes("123".as_bytes(), 10).unwrap());
995}