postchain_client/encoding/
gtv.rs

1//! GTV (Generic Type Value) encoding and decoding module
2//! 
3//! This module provides functionality for encoding and decoding GTV format, which is a flexible
4//! data serialization format supporting various data types including null, boolean, integer,
5//! string, arrays, dictionaries, and big integers. It uses ASN.1 encoding rules for data representation.
6//! 
7//! # Features
8//! 
9//! * Basic types: null, boolean, integer, string, byte array
10//! * Complex types: arrays, dictionaries
11//! * Special types: big integers, decimals
12//! * Transaction encoding/decoding
13//! * ASN.1-based encoding rules
14//! 
15//! # Examples
16//! 
17//! ```rust
18//! // Encoding a simple value
19//! let value = Params::Text("hello".to_string());
20//! let encoded = encode_value(&value);
21//! 
22//! // Decoding a value
23//! let decoded = decode(&encoded).unwrap();
24//! ```
25
26use crate::utils::{operation::{Operation, Params}, transaction::Transaction};
27
28use asn1::{Asn1Read, Asn1Readable, Asn1Write, ParseError};
29use std::collections::BTreeMap;
30
31#[derive(Asn1Read, Asn1Write, Debug, Clone)]
32pub enum Choice<'a> {
33    #[explicit(0)]
34    NULL(()),
35    #[explicit(1)]
36    OCTETSTRING(&'a [u8]),
37    #[explicit(2)]
38    UTF8STRING(asn1::Utf8String<'a>),
39    #[explicit(3)]
40    INTEGER(i64),
41    #[explicit(4)]
42    DICT(asn1::Sequence<'a>),
43    #[explicit(5)]
44    ARRAY(asn1::Sequence<'a>),
45    #[explicit(6)]
46    BIGINTEGER(asn1::BigInt<'a>),
47}
48
49#[derive(Debug)]
50pub enum GTVType {
51    Null = 0,
52    ByteArray = 1,
53    String = 2,
54    Integer = 3,
55    Dict = 4,
56    Array = 5,
57    BigInteger = 6,
58}
59
60pub trait GTVParams: Clone {
61    fn to_writer(&self, writer: &mut asn1::Writer) -> asn1::WriteResult;
62}
63
64pub fn write_explicit_element<T: asn1::Asn1Writable>(writer: &mut asn1::Writer, val: &T, tag: u32)
65  -> asn1::WriteResult {
66  let tag = asn1::explicit_tag(tag);
67  writer.write_tlv(tag, |dest| asn1::Writer::new(dest).write_element(val))
68}
69
70#[allow(unused_assignments)]
71impl<'a> GTVParams for Params {
72    fn to_writer(&self, writer: &mut asn1::Writer) -> asn1::WriteResult {
73        if let Params::Array(val) = self {
74            write_explicit_element(writer,
75                &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
76                    for v in val {
77                        v.to_writer(writer)?;
78                    }
79                    Ok(())
80                }),
81                5,
82            )?;
83            Ok(())
84        } else if let Params::Dict(val) = self {
85            write_explicit_element(writer,
86                &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
87                    for v in val {
88                        writer.write_element(&asn1::SequenceWriter::new(
89                            &|writer: &mut asn1::Writer| {
90                                writer.write_element(&asn1::Utf8String::new(v.0))?;
91                                v.1.to_writer(writer)?;
92                                Ok(())
93                            },
94                        ))?;
95                    }
96
97                    Ok(())
98                }),
99                4,
100            )?;
101            Ok(())
102        } else {
103            let mut decimal_to_string = String::new();
104            let mut bigint_to_vec_u8: Vec<u8> = Vec::new();
105
106            let gtv_choice = match self {
107                Params::Integer(val) => Choice::INTEGER(*val),
108                Params::Boolean(val) => Choice::INTEGER(*val as i64),
109                Params::Decimal(val) => {
110                    decimal_to_string = val.to_string();
111                    Choice::UTF8STRING(asn1::Utf8String::new(decimal_to_string.as_str()))
112                }
113                Params::Text(val) => Choice::UTF8STRING(asn1::Utf8String::new(val)),
114                Params::ByteArray(val) => Choice::OCTETSTRING(&val),
115                Params::BigInteger(val) => {
116                    let (sign, bytes) = val.to_bytes_be();
117
118                    if sign == num_bigint::Sign::Minus {
119                      let bytes1 = val.to_signed_bytes_be();
120                      bigint_to_vec_u8 = bytes1;
121                    } else {
122                      bigint_to_vec_u8 = bytes;
123                    }
124
125                    Choice::BIGINTEGER(asn1::BigInt::new(bigint_to_vec_u8.as_slice()).unwrap())
126                }
127                _ => Choice::NULL(())
128            };
129
130            writer.write_element(&gtv_choice)?;
131            Ok(())
132        }
133    }
134}
135
136/// Encodes a transaction into a byte vector using GTV format
137/// 
138/// # Arguments
139/// 
140/// * `tx` - Reference to the Transaction to be encoded
141/// 
142/// # Returns
143/// 
144/// * `Vec<u8>` - Encoded transaction as a byte vector
145pub fn encode_tx<'a>(tx: &Transaction<'a>) -> Vec<u8> {
146  asn1::write(|writer| {
147    write_explicit_element(writer,
148      &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
149          
150          write_explicit_element(writer,
151            &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
152
153              // Blockchain RID
154              writer.write_element(&Choice::OCTETSTRING(
155                &tx.blockchain_rid))?;
156
157              // Operations and args
158              write_explicit_element(writer,
159                &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
160 
161                  if let Some(operations) = &tx.operations {
162                    for operation in operations {
163                      encode_tx_body(writer, operation)?;
164                    }      
165                  }
166
167                  Ok(())
168              }), 5)?;
169
170
171              // Signers pubkeys
172              write_explicit_element(writer,
173                &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
174                
175                  if let Some(signers) = &tx.signers {
176                    for sig in signers {
177                      writer.write_element(&Choice::OCTETSTRING(&sig))?;
178                    }
179                  }
180
181                  Ok(())
182              }), 5)?;
183
184              Ok(())
185          }), 5)?;
186
187          // Signatures
188          write_explicit_element(writer,
189            &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
190             
191              if let Some(signatures) = &tx.signatures {
192                for sig in signatures {
193                  writer.write_element(&Choice::OCTETSTRING(&sig))?;
194                }
195              }
196
197              Ok(())
198          }), 5)?;
199
200        Ok(())
201      }),
202      5, )?;
203    Ok(())
204  }).unwrap()
205}
206
207/// Encodes a query and its arguments into GTV format
208/// 
209/// # Arguments
210/// 
211/// * `query_type` - The type of query to encode
212/// * `query_args` - Optional vector of query arguments as (name, value) pairs
213/// 
214/// # Returns
215/// 
216/// * `Vec<u8>` - Encoded query as a byte vector
217pub fn encode<'a>(
218    query_type: &str,
219    query_args: Option<&'a mut Vec<(&str, Params)>>,
220) -> Vec<u8> {
221    asn1::write(|writer| {
222        write_explicit_element(writer,
223            &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
224                writer.write_element(&Choice::UTF8STRING(asn1::Utf8String::new(query_type)))?;
225                encode_body(writer, &query_args)?;
226                Ok(())
227            }),
228            5,
229        )?;
230        Ok(())
231    })
232    .unwrap()
233}
234
235/// Encodes the body of a transaction operation
236/// 
237/// # Arguments
238/// 
239/// * `writer` - The ASN.1 writer to write to
240/// * `operation` - The operation to encode
241/// 
242/// # Returns
243/// 
244/// * `asn1::WriteResult` - Result of the write operation
245fn encode_tx_body<'a>(writer: &mut asn1::Writer, operation: &Operation<'a>) -> asn1::WriteResult {
246  write_explicit_element(writer, &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
247    // Operation name
248    write_explicit_element(writer,&asn1::Utf8String::new(&operation.operation_name.unwrap()), 2)?;
249    // Operation args
250    write_explicit_element(writer, &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
251      if let Some(operation_args) = &operation.list {
252        for arg in operation_args {
253          arg.to_writer(writer)?;
254        }
255      } else if let Some(operation_args) = &operation.dict {
256        write_explicit_element(writer, &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
257          for (_key, val) in operation_args {
258            val.to_writer(writer)?;
259          }
260          Ok(())
261        }), 5)?;
262      }
263      Ok(())
264    }), 5)?;
265    Ok(())
266  }), 5)?;
267  Ok(())
268}
269
270/// Encodes the body of a query
271/// 
272/// # Arguments
273/// 
274/// * `writer` - The ASN.1 writer to write to
275/// * `query_args` - Optional query arguments to encode
276/// 
277/// # Returns
278/// 
279/// * `asn1::WriteResult` - Result of the write operation
280fn encode_body<'a>(writer: &mut asn1::Writer,
281  query_args: &Option<&'a mut Vec<(&str, Params)>>)
282  -> asn1::WriteResult {
283  write_explicit_element(writer,
284      &asn1::SequenceWriter::new(&|writer: &mut asn1::Writer| {
285          if let Some(q_args) = &query_args {
286              let q_args_as_slice = q_args.iter().as_slice();
287              for (q_type, q_args) in q_args_as_slice {
288                  writer.write_element(&asn1::SequenceWriter::new(
289                      &|writer: &mut asn1::Writer| {
290                          writer.write_element(&asn1::Utf8String::new(&q_type))?;
291                          q_args.to_writer(writer)?;
292                          Ok(())
293                      },
294                  ))?;
295              }
296          }
297          Ok(())
298      }),
299      4,
300  )?;
301  Ok(())
302}
303
304/// Decodes a simple GTV value from a Choice enum
305/// 
306/// # Arguments
307/// 
308/// * `choice` - The Choice enum variant to decode
309/// 
310/// # Returns
311/// 
312/// * `Params` - The decoded parameter value
313fn decode_simple(choice: Choice) -> Params {
314  match choice {
315      Choice::INTEGER(val) =>
316        Params::Integer(val),
317      Choice::BIGINTEGER(val) => {
318        let result = if val.is_negative() {
319          num_bigint::BigInt::from_signed_bytes_be(val.as_bytes().try_into().unwrap())
320        } else {
321          num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, val.as_bytes().try_into().unwrap())
322        };
323        Params::BigInteger(result)
324      },
325      Choice::OCTETSTRING(val) =>
326        Params::ByteArray(val.to_vec()),
327      Choice::UTF8STRING(val) =>
328        Params::Text(val.as_str().to_string()),
329      _ => 
330        Params::Null
331  }
332}
333
334/// Decodes a sequence of values into an array
335/// 
336/// # Arguments
337/// 
338/// * `parser` - The ASN.1 parser to read from
339/// * `vec_array` - Vector to store the decoded values
340fn decode_sequence_array<'a>(parser: &mut asn1::Parser<'a>, vec_array: &mut Vec<Params>) {
341  while let Ok(val) = Choice::parse(parser) {
342    let op_val = match val {
343        Choice::ARRAY(seq) => {
344          let res: Result<Params, ParseError> = seq.parse(|parser| {
345            let mut vect_array_new: Vec<Params> = Vec::new();
346            decode_sequence_array(parser, &mut vect_array_new);
347            Ok(Params::Array(vect_array_new))
348          });
349          res.unwrap()
350        }
351        Choice::DICT(seq) => {
352          let res: Result<Params, ParseError> = seq.parse(|parser| {
353            let mut btree_map_new: BTreeMap<String, Params> = BTreeMap::new();
354            decode_sequence_dict(parser, &mut btree_map_new);
355            Ok(Params::Dict(btree_map_new))
356          });
357          res.unwrap()
358        }
359        _ =>
360          decode_simple(val)
361    };
362    vec_array.push(op_val);
363  }
364}
365
366/// Decodes a sequence of key-value pairs into a dictionary
367/// 
368/// # Arguments
369/// 
370/// * `parser` - The ASN.1 parser to read from
371/// * `btreemap` - BTreeMap to store the decoded key-value pairs
372fn decode_sequence_dict<'a>(parser: &mut asn1::Parser<'a>, btreemap: &mut BTreeMap<String, Params>) {
373  loop {
374      let seq = parser.read_element::<asn1::Sequence>();
375      if let Err(_) = seq {
376          break;
377      }
378      let res: Result<(&'a str, Params), ParseError> = seq.unwrap().parse(|parser| {
379        let key = parser.read_element::<asn1::Utf8String>()?;
380        let val = Choice::parse(parser).unwrap();
381
382        let op_val = match val {
383          Choice::DICT(seq) => {
384            let res: Result<Params, ParseError> = seq.parse(|parser| {
385              let mut btree_map_new: BTreeMap<String, Params> = BTreeMap::new();
386              decode_sequence_dict(parser, &mut btree_map_new);
387              Ok(Params::Dict(btree_map_new))
388            });
389            res.unwrap()
390          }
391          Choice::ARRAY(seq) => {
392            let res: Result<Params, ParseError> = seq.parse(|parser| {
393              let mut vect_array_new: Vec<Params> = Vec::new();
394              decode_sequence_array(parser, &mut vect_array_new);
395              Ok(Params::Array(vect_array_new))
396            });
397            res.unwrap()
398          },
399          _ => 
400            decode_simple(val)      
401        };
402
403        Ok((key.as_str(), op_val))
404      });
405
406      let res: (&'a str, Params) = res.unwrap();
407
408      btreemap.insert(res.0.to_string(), res.1);
409  }
410}
411
412/// Decodes a byte slice into a GTV value
413/// 
414/// # Arguments
415/// 
416/// * `data` - Byte slice containing the encoded GTV data
417/// 
418/// # Returns
419/// 
420/// * `Result<Params, ParseError>` - The decoded value or an error if decoding fails
421pub fn decode<'a>(data: &'a [u8]) -> Result<Params, ParseError> {
422  let tag = asn1::Tag::from_bytes(data).unwrap();
423  let tag_num = tag.0.as_u8().unwrap() & 0x1f;
424
425  if vec![0, 1, 2, 3, 6].contains(&tag_num) {
426    asn1::parse(data, |d| {
427        let res_choice = Choice::parse(d);
428        match res_choice {
429            Ok(val) => Ok(decode_simple(val)),
430            Err(error) => Err(error),
431        }
432    })
433  } else {
434    if tag_num == 4 {
435      let result = asn1::parse_single::<asn1::Explicit<asn1::Sequence, 4>>(data).unwrap();
436      result.into_inner().parse(|parser| {
437        let mut btree_map_new: BTreeMap<String, Params> = BTreeMap::new();
438        decode_sequence_dict(parser, &mut btree_map_new);
439        Ok(Params::Dict(btree_map_new))
440      })
441    } else if tag_num == 5 {
442      let result = asn1::parse_single::<asn1::Explicit<asn1::Sequence, 5>>(data).unwrap();
443      result.into_inner().parse(|parser|{
444        let mut vect_array_new: Vec<Params> = Vec::new();
445        decode_sequence_array(parser, &mut vect_array_new);
446        Ok(Params::Array(vect_array_new))
447      })
448    } else {
449      Ok(Params::Null)
450    }
451  }
452}
453
454/// Decodes a transaction from a byte slice
455/// 
456/// # Arguments
457/// 
458/// * `data` - Byte slice containing the encoded transaction
459/// 
460/// # Returns
461/// 
462/// * `Result<Params, ParseError>` - The decoded transaction or an error if decoding fails
463pub fn decode_tx<'a>(data: &'a [u8]) -> Result<Params, ParseError> {
464  decode(data)
465}
466
467/// Encodes a single GTV value into a byte vector
468/// 
469/// # Arguments
470/// 
471/// * `value` - The value to encode
472/// 
473/// # Returns
474/// 
475/// * `Vec<u8>` - The encoded value as a byte vector
476pub fn encode_value(value: &Params) -> Vec<u8> {
477  asn1::write(|writer| {
478      value.to_writer(writer)?;
479      Ok(())
480  }).unwrap()
481}
482
483/// Encodes a GTV value and returns it as a hexadecimal string
484/// 
485/// # Arguments
486/// 
487/// * `value` - The value to encode
488/// 
489/// # Returns
490/// 
491/// * `String` - Hexadecimal representation of the encoded value
492pub fn encode_value_hex_encode(value: &Params) -> String {
493  hex::encode(encode_value(value))
494}
495
496/// Converts a transaction into a GTV representation for visualization
497/// 
498/// # Arguments
499/// 
500/// * `tx` - Reference to the transaction to convert
501/// 
502/// # Returns
503/// 
504/// * `Params` - GTV representation of the transaction
505pub fn to_draw_gtx<'a>(tx: &'a Transaction<'a>) -> Params {
506  let mut signers: Vec<Params> = vec![];
507  let mut operations:Vec<Params> = vec![];
508
509  if let Some(raw_signers) = &tx.signers {
510    for signer in raw_signers {
511      signers.push(Params::ByteArray(signer.to_vec()));
512    }
513  }
514
515  for op in &tx.operations.clone().unwrap() {
516    let mut op_args: Vec<Params> = vec![];
517
518    if let Some(op_list) = &op.list {
519      for arg in op_list {
520        op_args.push(arg.clone());
521      }
522    } else if let Some(op_dict) = &op.dict {
523      for (_key, value) in op_dict {
524        op_args.push(value.clone());
525      }
526    }
527
528    operations.push(Params::Array(vec![
529      Params::Text(op.operation_name.unwrap().to_string()),
530      Params::Array(op_args)
531    ]));
532  }
533
534  Params::Array(vec![
535    Params::ByteArray(tx.blockchain_rid.to_vec()),
536    Params::Array(operations),
537    Params::Array(signers)
538  ])
539} 
540
541#[allow(dead_code)]
542/// Helper function for testing GTV encoding/decoding roundtrips
543/// 
544/// # Arguments
545/// 
546/// * `query_args` - Optional query arguments to test
547/// * `expected_value` - Expected hexadecimal string after encoding
548fn assert_roundtrips<'a>(
549  query_args: Option<&'a mut Vec<(&str, Params)>>,
550  expected_value: &str) {
551    let result = asn1::write(|writer| {
552      encode_body(writer, &query_args)?;
553      Ok(())
554    });
555    assert_eq!(hex::encode(result.unwrap()), expected_value);
556}
557
558#[allow(dead_code)]
559/// Helper function for testing GTV value encoding/decoding roundtrips
560/// 
561/// # Arguments
562/// 
563/// * `value` - Value to test
564/// * `expected_decode` - Expected decoded value
565/// * `expected_value` - Expected hexadecimal string after encoding
566fn assert_roundtrips_value<'a>(
567  value: &Params,
568  expected_decode: &Params,
569  expected_value: &str) {
570    let encode_result = encode_value(&value);
571    assert_eq!(expected_value, hex::encode(encode_result.clone()));
572
573    let decode_result = decode(&encode_result).unwrap();
574    assert_eq!(expected_decode, &decode_result);
575} 
576
577#[test]
578fn gtv_encode_value_null() {
579  assert_roundtrips_value(&Params::Null, &Params::Null, "a0020500")
580}
581
582#[test]
583fn gtv_encode_value_boolean() {
584  assert_roundtrips_value(&Params::Boolean(true), &Params::Integer(1), "a303020101");
585  assert_roundtrips_value(&Params::Boolean(false), &Params::Integer(0),"a303020100")
586}
587
588#[test]
589fn gtv_encode_value_integer() {
590  assert_roundtrips_value(&Params::Integer(999), &Params::Integer(999), "a304020203e7")
591}
592
593#[test]
594fn gtv_encode_value_decimal() {
595  use std::str::FromStr;
596  assert_roundtrips_value(&Params::Decimal(bigdecimal::BigDecimal::from_str("999.999").unwrap()), &Params::Text("999.999".to_string()), "a2090c073939392e393939")
597}
598
599#[test]
600fn gtv_encode_value_text() {
601  assert_roundtrips_value(&Params::Text("hello!".to_string()), &Params::Text("hello!".to_string()), "a2080c0668656c6c6f21")
602}
603
604#[test]
605fn gtv_encode_value_bytearray() {
606  assert_roundtrips_value(&Params::ByteArray(b"123456789".to_vec()), &Params::ByteArray(b"123456789".to_vec()), "a10b0409313233343536373839")
607}
608
609#[test]
610fn gtv_encode_value_array() {
611  let array = Params::Array(vec![
612          Params::Text("foo1".to_string()),
613          Params::Text("foo2".to_string()),
614      ]);
615  assert_roundtrips_value(&array, &array, "a5123010a2060c04666f6f31a2060c04666f6f32")
616}
617
618#[test]
619fn gtv_encode_value_dict() {
620  use std::collections::BTreeMap;
621  let mut data: BTreeMap<String, Params> = BTreeMap::new();
622  let mut data1: BTreeMap<String, Params> = BTreeMap::new();
623  let mut data2: BTreeMap<String, Params> = BTreeMap::new();
624
625  data2.insert("foo1_1_1".to_string(), Params::Integer(1000));
626
627  data1.insert("foo1_1".to_string(), Params::Dict(data2));
628  data1.insert("foo1_2".to_string(), Params::Text("hello!".to_string()));
629
630  data.insert("foo".to_string(), Params::Text("bar".to_string()));
631  data.insert("foo1".to_string(), Params::Dict(data1));
632
633  let dict = Params::Dict(data);
634  assert_roundtrips_value(&dict, &dict, "a450304e300c0c03666f6fa2050c03626172303e0c04666f6f31a4363034301e0c06666f6f315f31a414301230100c08666f6f315f315f31a304020203e830120c06666f6f315f32a2080c0668656c6c6f21")
635}
636
637#[test]
638fn gtv_encode_value_big_integer() {
639  use std::str::FromStr;
640
641  let max_i128: i128 = i128::MAX;
642  let data = num_bigint::BigInt::from_str(max_i128.to_string().as_str()).unwrap();
643  assert_roundtrips_value(&Params::BigInteger(data.clone()), &Params::BigInteger(data), "a61202107fffffffffffffffffffffffffffffff");
644}
645
646#[test]
647fn gtv_test_sequence_with_empty() {
648  assert_roundtrips(None, "a4023000");
649}
650
651#[test]
652fn gtv_test_sequence_with_boolean() {
653  assert_roundtrips(Some(&mut vec![("foo", Params::Boolean(true))]), 
654  "a40e300c300a0c03666f6fa303020101");
655}
656
657#[test]
658fn gtv_test_sequence_with_string() {
659  assert_roundtrips(Some(&mut vec![("foo", Params::Text("bar".to_string()))]), 
660  "a410300e300c0c03666f6fa2050c03626172");
661}
662
663#[test]
664fn gtv_test_sequence_with_octet_string() {
665  assert_roundtrips(Some(&mut vec![("foo", Params::ByteArray("bar".as_bytes().to_vec()))]), 
666  "a410300e300c0c03666f6fa1050403626172");
667}
668
669#[test]
670fn gtv_test_sequence_with_number() {
671  assert_roundtrips(Some(&mut vec![("foo", Params::Integer(9999))]), 
672  "a40f300d300b0c03666f6fa3040202270f");
673}
674
675#[test]
676fn gtv_test_sequence_with_negative_number() {
677  assert_roundtrips(Some(&mut vec![("foo", Params::Integer(-9999))]), 
678  "a40f300d300b0c03666f6fa3040202d8f1");
679}
680
681#[test]
682fn gtv_test_sequence_with_decimal() {
683  use std::str::FromStr;
684  assert_roundtrips(Some(&mut vec![("foo", Params::Decimal(bigdecimal::BigDecimal::from_str("99.99").unwrap()))]), 
685  "a4123010300e0c03666f6fa2070c0539392e3939");
686}
687
688#[test]
689fn gtv_test_sequence_with_negative_decimal() {
690  use std::str::FromStr;
691  assert_roundtrips(Some(&mut vec![("foo", Params::Decimal(bigdecimal::BigDecimal::from_str("-99.99").unwrap()))]),
692  "a4133011300f0c03666f6fa2080c062d39392e3939");
693}
694
695#[test]
696fn gtv_test_sequence_with_json() {
697  let data = serde_json::json!({
698            "foo": "bar",
699            "bar": 9,
700            "foo": 9.00
701        }).to_string();
702  assert_roundtrips(Some(&mut vec![("foo", Params::Text(data))]), 
703  "a420301e301c0c03666f6fa2150c137b22626172223a392c22666f6f223a392e307d");
704}
705
706#[test]
707fn gtv_test_sequence_with_big_integer() {
708  use std::str::FromStr;
709
710  let max_i128: i128 = i128::MAX;
711  let data = num_bigint::BigInt::from_str(max_i128.to_string().as_str()).unwrap();
712  assert_roundtrips(Some(&mut vec![("foo", Params::BigInteger(data))]), 
713  "a41d301b30190c03666f6fa61202107fffffffffffffffffffffffffffffff");
714}
715
716#[test]
717fn gtv_test_sequence_with_negative_big_integer() {
718  use std::str::FromStr;
719
720  let min_i128: i128 = i128::MIN;
721  let data = num_bigint::BigInt::from_str(min_i128.to_string().as_str()).unwrap();
722  assert_roundtrips(Some(&mut vec![("foo", Params::BigInteger(data))]), 
723  "a41d301b30190c03666f6fa612021080000000000000000000000000000000");
724
725  let h_data = "a41d301b30190c03666f6fa6120210ff123b1a8199614ad13ab29a33fba0eb";
726
727  let data = num_bigint::BigInt::from_str("-1234567890123456789123456789123456789").unwrap();
728  assert_roundtrips(Some(&mut vec![("foo", Params::BigInteger(data.clone()))]), 
729  h_data);
730
731  let hex_decode_data = hex::decode(h_data).unwrap();
732  let result = decode(&hex_decode_data).unwrap();
733
734  if let Params::Dict(dict) = result {
735    let bi: num_bigint::BigInt = dict["foo"].clone().into();
736    assert_eq!(data, bi);
737  }
738}
739
740#[test]
741fn gtv_test_sequence_with_array() {
742  let data = &mut vec![(
743      "foo",
744      Params::Array(vec![
745          Params::Text("bar1".to_string()),
746          Params::Text("bar2".to_string()),
747      ]),
748  )];
749  assert_roundtrips(Some(data), 
750  "a41d301b30190c03666f6fa5123010a2060c0462617231a2060c0462617232");
751}
752
753#[test]
754fn gtv_test_sequence_with_dict() {
755  use std::collections::BTreeMap;
756
757  let mut params: BTreeMap<String, Params> = BTreeMap::new();
758  params.insert("foo".to_string(), Params::Text("bar".to_string()));
759  params.insert("foo1".to_string(), Params::Text("bar1".to_string()));
760
761  let data = &mut vec![("foo",  Params::Dict(params))];
762
763  assert_roundtrips(Some(data), 
764  "a42b302930270c03666f6fa420301e300c0c03666f6fa2050c03626172300e0c04666f6f31a2060c0462617231");
765}
766
767#[test]
768fn gtv_test_sequence_with_nested_dict() {
769  use std::collections::BTreeMap;
770
771  let mut dict1: BTreeMap<String, Params> = BTreeMap::new();
772  let mut dict2: BTreeMap<String, Params> = BTreeMap::new();
773  let dict3: BTreeMap<String, Params> = BTreeMap::new();
774
775  dict1.insert("dict1_foo".to_string(), Params::Text("dict1_bar".to_string()));
776
777  dict2.insert("dict2_foo".to_string(), Params::Text("dict2_bar".to_string()));
778  dict2.insert("dict2_foo1".to_string(), Params::Text("dict2_bar1".to_string()));
779  
780  dict2.insert("dict3_empty_data".to_string(), Params::Dict(dict3));
781
782  dict1.insert("dict2_data".to_string(), Params::Dict(dict2));
783
784  let data = &mut vec![("foo",  Params::Dict(dict1))];
785
786  assert_roundtrips(Some(data), 
787  "a481893081863081830c03666f6fa47c307a30180c0964696374315f666f6fa20b0c0964696374315f626172305e0c0a64696374325f64617461a450304e30180c0964696374325f666f6fa20b0c0964696374325f626172301a0c0a64696374325f666f6f31a20c0c0a64696374325f6261723130160c1064696374335f656d7074795f64617461a4023000");
788}
789
790#[test]
791fn gtv_test_sequence_with_nested_dict_array() {
792  use std::collections::BTreeMap;
793
794  let mut dict1: BTreeMap<String, Params> = BTreeMap::new();
795  let mut dict2: BTreeMap<String, Params> = BTreeMap::new();
796  let mut dict3: BTreeMap<String, Params> = BTreeMap::new();
797
798  dict2.insert("dict2_foo".to_string(), Params::Text("dict2_bar".to_string()));
799  dict3.insert("dict3_foo".to_string(), Params::Text("dict3_bar".to_string()));
800
801  let array1 = vec![
802    Params::Dict(dict2), Params::Dict(dict3)];
803
804  dict1.insert("array1".to_string(), Params::Array(array1));
805
806  let data = &mut vec![("foo",  Params::Dict(dict1))];
807
808  assert_roundtrips(Some(data), 
809  "a457305530530c03666f6fa44c304a30480c06617272617931a53e303ca41c301a30180c0964696374325f666f6fa20b0c0964696374325f626172a41c301a30180c0964696374335f666f6fa20b0c0964696374335f626172");
810}
811
812#[allow(dead_code)]
813/// Helper function for testing simple GTV value encoding
814/// 
815/// # Arguments
816/// 
817/// * `op` - Value to encode
818/// * `expected_value` - Expected hexadecimal string after encoding
819fn assert_roundtrips_simple(op: Params, expected_value: &str) {
820  let result = asn1::write(|writer| {
821      op.to_writer(writer)?;
822      Ok(())
823    });
824  assert_eq!(hex::encode(result.unwrap()), expected_value);
825}
826
827#[test]
828fn gtv_test_simple_null() {
829  assert_roundtrips_simple(Params::Null, "a0020500");
830}
831
832#[test]
833fn gtv_test_simple_boolean() {
834  assert_roundtrips_simple(Params::Boolean(true), "a303020101");
835  assert_roundtrips_simple(Params::Boolean(false), "a303020100");
836}
837
838#[test]
839fn gtv_test_simple_integer() {
840  assert_roundtrips_simple(Params::Integer(99999), "a305020301869f");
841}
842
843#[test]
844fn gtv_test_simple_big_integer() {
845  assert_roundtrips_simple(Params::BigInteger(num_bigint::BigInt::from(1234567890123456789 as i128)), "a60a0208112210f47de98115");
846}
847
848#[test]
849fn gtv_test_simple_decimal() {
850  use std::str::FromStr;
851  assert_roundtrips_simple(Params::Decimal(bigdecimal::BigDecimal::from_str("99.999").unwrap()), "a2080c0639392e393939");
852}
853
854#[test]
855fn gtv_test_simple_string() {
856  assert_roundtrips_simple(Params::Text("abcABC123".to_string()), "a20b0c09616263414243313233");
857  assert_roundtrips_simple(Params::Text("utf-8 unicode Trái Tim Ngục Tù ...!@#$%^&*()".to_string()), "a2320c307574662d3820756e69636f6465205472c3a1692054696d204e67e1bba5632054c3b9202e2e2e21402324255e262a2829");
858}
859
860#[test]
861fn gtv_test_simple_byte_array() {
862  assert_roundtrips_simple(Params::ByteArray(b"123456abcedf".to_vec()), "a10e040c313233343536616263656466");
863}
864
865#[test]
866fn gtv_test_simple_array() {
867  assert_roundtrips_simple(Params::Array(vec![
868    Params::Text("foo".to_string()), Params::Integer(1)
869  ]), "a50e300ca2050c03666f6fa303020101");
870}
871
872#[test]
873fn gtv_test_simple_dict() {
874  use std::collections::BTreeMap;
875  let mut data: BTreeMap<String, Params> = BTreeMap::new();
876  data.insert("foo".to_string(), Params::Text("bar".to_string()));
877  assert_roundtrips_simple(Params::Dict(data), "a410300e300c0c03666f6fa2050c03626172");
878}
879
880#[allow(dead_code)]
881/// Helper function for testing simple GTV value decoding
882/// 
883/// # Arguments
884/// 
885/// * `data` - Hexadecimal string to decode
886/// * `expected_value` - Expected decoded value
887fn assert_roundtrips_simple_decode(data: &str, expected_value: Params) {
888  let hex_decode_data = hex::decode(data).unwrap();
889  let result = decode(&hex_decode_data).unwrap();
890  assert_eq!(result, expected_value);
891}
892
893#[test]
894fn gtv_test_simple_null_decode() {
895  assert_roundtrips_simple_decode("a0020500", Params::Null);
896}
897
898#[test]
899fn gtv_test_simple_big_integer_decode() {
900  assert_roundtrips_simple_decode("a60a0208112210f47de98115", 
901    Params::BigInteger(num_bigint::BigInt::from(1234567890123456789 as i128)));
902}
903
904#[test]
905fn gtv_test_simple_integer_decode() {
906  assert_roundtrips_simple_decode("a305020301869f", Params::Integer(99999));
907}
908
909#[test]
910fn gtv_test_simple_decimal_decode() {
911  assert_roundtrips_simple_decode("a2080c0639392e393939", Params::Text("99.999".to_string()));
912}
913
914#[test]
915fn gtv_test_simple_string_decode() {
916  assert_roundtrips_simple_decode("a2320c307574662d3820756e69636f6465205472c3a1692054696d204e67e1bba5632054c3b9202e2e2e21402324255e262a2829",
917    Params::Text("utf-8 unicode Trái Tim Ngục Tù ...!@#$%^&*()".to_string()))
918}
919
920#[test]
921fn gtv_test_simple_bytearray_with_hex_decode() {
922  assert_roundtrips_simple_decode("a53b3039a5373035a12304210373599a61cc6b3bc02a78c34313e1737ae9cfd56b9bb24360b437d469efdf3b15a20e0c0c73616d706c655f76616c7565",
923  Params::Array(vec![
924    Params::Array(vec![
925      Params::ByteArray(hex::decode("0373599A61CC6B3BC02A78C34313E1737AE9CFD56B9BB24360B437D469EFDF3B15").unwrap()),
926      Params::Text("sample_value".to_string())
927    ])
928  ]))
929}
930
931#[test]
932fn gtv_test_sequence_simple_array_decode() {
933  let data = Params::Array(vec![
934    Params::Text("foo".to_string()), Params::Integer(1),
935    Params::Text("bar".to_string()), Params::Integer(2),
936    Params::Array(vec![]),
937    Params::Text("ca".to_string()), Params::Integer(3),
938    Params::Array(vec![
939      Params::Integer(1111),
940      Params::Array(vec![
941        Params::Integer(2222),
942        Params::Integer(3333),
943      ])
944    ]),
945  ]);
946
947  let result = asn1::write(|writer| {
948      data.to_writer(writer)?; Ok(()) }).unwrap();
949  
950  assert_eq!(data, decode(result.as_slice()).unwrap());
951}
952
953#[test]
954fn gtv_test_sequence_simple_dict_decode() {
955  let mut data_btreemap: BTreeMap<String, Params> = BTreeMap::new();
956
957  data_btreemap.insert("foo".to_string(), Params::Text("bar".to_string()));
958  data_btreemap.insert("status".to_string(), Params::ByteArray("OK".as_bytes().to_vec()));
959
960  let data = Params::Dict(data_btreemap);
961
962  let result = asn1::write(|writer| {
963    data.to_writer(writer)?; Ok(()) }).unwrap();
964
965  assert_eq!(data, decode(result.as_slice()).unwrap());  
966}
967
968#[test]
969fn gtv_test_sequence_complex_mix_dict_array_decode() {
970  use std::collections::BTreeMap;
971  let mut data_btreemap: BTreeMap<String, Params> = BTreeMap::new();
972  let mut dict_in: BTreeMap<String, Params> = BTreeMap::new();
973
974  dict_in.insert("foo".to_string(), Params::Text("bar".to_string()));
975
976  data_btreemap.insert("status".to_string(), Params::Text("dict_bar".to_string()));
977  data_btreemap.insert("command".to_string(), Params::Text("dict_bar2".to_string()));
978  data_btreemap.insert("state".to_string(), Params::Integer(123));
979  data_btreemap.insert("dict".to_string(), Params::Dict(dict_in));
980  data_btreemap.insert("array".to_string(), Params::Array(vec![
981    Params::Text("test array".to_string()),
982    Params::BigInteger(num_bigint::BigInt::from(123456 as i128)),
983    Params::Array(vec![
984      Params::Text("test array 2".to_string())
985    ])
986  ]));
987  
988  let data = Params::Dict(data_btreemap);
989
990  let result = asn1::write(|writer| {
991    data.to_writer(writer)?; Ok(()) }).unwrap();
992
993  assert_eq!(data, decode(result.as_slice()).unwrap());
994}