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