amadeus_utils/
safe_etf.rs

1use eetf::Term;
2use num_bigint::BigInt;
3use std::cmp::Ordering;
4
5/// Convert u64 to Term (FixInteger if fits in i32, otherwise BigInteger)
6#[inline]
7pub fn u64_to_term(value: u64) -> Term {
8    if value <= i32::MAX as u64 {
9        Term::FixInteger(eetf::FixInteger { value: value as i32 })
10    } else {
11        Term::BigInteger(eetf::BigInteger::from(value))
12    }
13}
14
15#[inline]
16pub fn i64_to_term(value: i64) -> Term {
17    if value <= i32::MAX as i64 {
18        Term::FixInteger(eetf::FixInteger { value: value as i32 })
19    } else {
20        Term::BigInteger(eetf::BigInteger::from(value))
21    }
22}
23
24/// Convert i128 to Term (FixInteger if fits in i32, otherwise BigInteger)
25#[inline]
26pub fn i128_to_term(value: i128) -> Term {
27    if value >= i32::MIN as i128 && value <= i32::MAX as i128 {
28        Term::FixInteger(eetf::FixInteger { value: value as i32 })
29    } else if value >= 0 && value <= u64::MAX as i128 {
30        Term::BigInteger(eetf::BigInteger::from(value as u64))
31    } else {
32        // For values outside u64 range or negative, create BigInteger manually
33        Term::BigInteger(eetf::BigInteger { value: BigInt::from(value) })
34    }
35}
36
37/// Convert u32 to Term (FixInteger if fits in i32, otherwise BigInteger)
38#[inline]
39pub fn u32_to_term(value: u32) -> Term {
40    if value <= i32::MAX as u32 {
41        Term::FixInteger(eetf::FixInteger { value: value as i32 })
42    } else {
43        Term::BigInteger(eetf::BigInteger::from(value as u64))
44    }
45}
46
47/// Convert u32 to Term (FixInteger if fits in i32, otherwise BigInteger)
48#[inline]
49pub fn i32_to_term(value: i32) -> Term {
50    Term::FixInteger(eetf::FixInteger { value })
51}
52
53/// Encode an EETF term using small atoms (tag 119) instead of legacy atoms (tag 100)
54/// This ensures compatibility with Elixir's [:safe] option which rejects old atom encoding
55pub fn encode_safe(term: &Term) -> Vec<u8> {
56    let mut buf = Vec::new();
57    buf.push(131); // ETF version marker
58    encode_term_with_small_atoms(term, &mut buf);
59    buf
60}
61
62/// Encode an EETF with small atoms ([:safe]) and [:deterministic]
63pub fn encode_safe_deterministic(term: &Term) -> Vec<u8> {
64    let mut buf = Vec::new();
65    buf.push(131); // ETF version marker
66    encode_map_safe_deterministic(term, &mut buf);
67    buf
68}
69
70/// Compare two terms according to Erlang's term ordering hierarchy
71fn compare_terms(a: &Term, b: &Term) -> Ordering {
72    let type_order = |term: &Term| -> u8 {
73        match term {
74            Term::FixInteger(_) | Term::BigInteger(_) | Term::Float(_) => 1,
75            Term::Atom(_) => 2,
76            Term::Reference(_) => 3,
77            Term::Port(_) => 4,
78            Term::Pid(_) => 5,
79            Term::Tuple(_) => 6,
80            Term::Map(_) => 7,
81            Term::List(_) | Term::ImproperList(_) => 8,
82            Term::Binary(_) | Term::BitBinary(_) | Term::ByteList(_) => 9,
83            Term::ExternalFun(_) | Term::InternalFun(_) => 10,
84        }
85    };
86
87    let a_type = type_order(a);
88    let b_type = type_order(b);
89
90    match a_type.cmp(&b_type) {
91        Ordering::Equal => {
92            match (a, b) {
93                // within number types, compare by numeric value,
94                // but integers come before floats in ETF ordering
95                (Term::FixInteger(a_int), Term::FixInteger(b_int)) => a_int.value.cmp(&b_int.value),
96                (Term::BigInteger(a_big), Term::BigInteger(b_big)) => a_big.value.cmp(&b_big.value),
97                (Term::Float(a_float), Term::Float(b_float)) => {
98                    a_float.value.partial_cmp(&b_float.value).unwrap_or(Ordering::Equal)
99                }
100
101                // integers come before floats in ETF format
102                (Term::FixInteger(_), Term::Float(_)) => Ordering::Less,
103                (Term::Float(_), Term::FixInteger(_)) => Ordering::Greater,
104                (Term::BigInteger(_), Term::Float(_)) => Ordering::Less,
105                (Term::Float(_), Term::BigInteger(_)) => Ordering::Greater,
106                // small int come before big int
107                (Term::FixInteger(_), Term::BigInteger(_)) => Ordering::Less,
108                (Term::BigInteger(_), Term::FixInteger(_)) => Ordering::Greater,
109
110                (Term::Atom(a_atom), Term::Atom(b_atom)) => a_atom.name.cmp(&b_atom.name),
111
112                // binaries are sorted by lexicographic byte comparison
113                (Term::Binary(a_bin), Term::Binary(b_bin)) => a_bin.bytes.cmp(&b_bin.bytes),
114                (Term::ByteList(a_bytes), Term::ByteList(b_bytes)) => a_bytes.bytes.cmp(&b_bytes.bytes),
115
116                // for other types within the same category, use string representation as fallback
117                _ => format!("{:?}", a).cmp(&format!("{:?}", b)),
118            }
119        }
120        other => other,
121    }
122}
123
124/// Encode a term with deterministic ordering (maps have sorted keys)
125fn encode_map_safe_deterministic(term: &Term, buf: &mut Vec<u8>) {
126    match term {
127        Term::Map(map) => {
128            let mut sorted_pairs: Vec<_> = map.map.iter().collect();
129            sorted_pairs.sort_by(|(a, _), (b, _)| compare_terms(a, b));
130
131            buf.push(116); // map tag
132            buf.extend_from_slice(&(sorted_pairs.len() as u32).to_be_bytes());
133
134            for (key, value) in sorted_pairs {
135                encode_map_safe_deterministic(key, buf);
136                encode_map_safe_deterministic(value, buf);
137            }
138        }
139        _ => {
140            // use the safe encoding but recurse with deterministic encoding for nested terms
141            encode_term_safe_deterministic(term, buf);
142        }
143    }
144}
145
146/// Encode term with small atoms and deterministic ordering for nested structures
147fn encode_term_safe_deterministic(term: &Term, buf: &mut Vec<u8>) {
148    match term {
149        Term::Atom(atom) => {
150            let name_bytes = atom.name.as_bytes();
151            if name_bytes.len() <= 255 {
152                buf.push(119); // small atom
153                buf.push(name_bytes.len() as u8);
154                buf.extend_from_slice(name_bytes);
155            } else {
156                buf.push(118); // atom_utf8
157                buf.extend_from_slice(&(name_bytes.len() as u16).to_be_bytes());
158                buf.extend_from_slice(name_bytes);
159            }
160        }
161        Term::List(list) => {
162            if list.elements.is_empty() {
163                buf.push(106); // nil
164            } else {
165                buf.push(108); // list
166                buf.extend_from_slice(&(list.elements.len() as u32).to_be_bytes());
167                for element in &list.elements {
168                    encode_map_safe_deterministic(element, buf); // Recurse with deterministic ordering
169                }
170                buf.push(106); // tail (nil)
171            }
172        }
173        Term::ImproperList(improper) => {
174            buf.push(108); // list
175            buf.extend_from_slice(&(improper.elements.len() as u32).to_be_bytes());
176            for element in &improper.elements {
177                encode_map_safe_deterministic(element, buf); // Recurse with deterministic ordering
178            }
179            encode_map_safe_deterministic(&improper.last, buf); // tail
180        }
181        Term::Tuple(tuple) => {
182            if tuple.elements.len() <= 255 {
183                buf.push(104); // small_tuple
184                buf.push(tuple.elements.len() as u8);
185            } else {
186                buf.push(105); // large_tuple
187                buf.extend_from_slice(&(tuple.elements.len() as u32).to_be_bytes());
188            }
189            for element in &tuple.elements {
190                encode_map_safe_deterministic(element, buf); // Recurse with deterministic ordering
191            }
192        }
193        Term::Map(_map) => {
194            // This shouldn't happen as maps are handled in encode_term_deterministic
195            // But handle it anyway for safety
196            encode_map_safe_deterministic(term, buf);
197        }
198        _ => {
199            // For all other types, use the existing small atoms encoding
200            encode_term_with_small_atoms(term, buf);
201        }
202    }
203}
204
205fn encode_term_with_small_atoms(term: &Term, buf: &mut Vec<u8>) {
206    match term {
207        Term::Atom(atom) => {
208            // Use small atom (tag 119) instead of legacy atom (tag 100)
209            let name_bytes = atom.name.as_bytes();
210            if name_bytes.len() <= 255 {
211                buf.push(119); // small atom
212                buf.push(name_bytes.len() as u8);
213                buf.extend_from_slice(name_bytes);
214            } else {
215                // For atoms longer than 255 bytes, use atom_utf8 (tag 118)
216                buf.push(118); // atom_utf8
217                buf.extend_from_slice(&(name_bytes.len() as u16).to_be_bytes());
218                buf.extend_from_slice(name_bytes);
219            }
220        }
221        Term::Binary(binary) => {
222            buf.push(109); // binary
223            buf.extend_from_slice(&(binary.bytes.len() as u32).to_be_bytes());
224            buf.extend_from_slice(&binary.bytes);
225        }
226        Term::FixInteger(fix_int) => {
227            if fix_int.value >= 0 && fix_int.value <= 255 {
228                buf.push(97); // small_integer
229                buf.push(fix_int.value as u8);
230            } else {
231                buf.push(98); // integer
232                buf.extend_from_slice(&fix_int.value.to_be_bytes());
233            }
234        }
235        Term::BigInteger(big_int) => {
236            // Convert big integer to bytes representation (little-endian for ETF format)
237            let bytes = big_int.value.to_bytes_le().1;
238            if bytes.len() <= 255 {
239                buf.push(110); // small_big
240                buf.push(bytes.len() as u8);
241                buf.push(if big_int.value >= 0.into() { 0 } else { 1 }); // sign
242            } else {
243                buf.push(111); // large_big
244                buf.extend_from_slice(&(bytes.len() as u32).to_be_bytes());
245                buf.push(if big_int.value >= 0.into() { 0 } else { 1 }); // sign
246            }
247            buf.extend_from_slice(&bytes);
248        }
249        Term::List(list) => {
250            if list.elements.is_empty() {
251                buf.push(106); // nil
252            } else {
253                buf.push(108); // list
254                buf.extend_from_slice(&(list.elements.len() as u32).to_be_bytes());
255                for element in &list.elements {
256                    encode_term_with_small_atoms(element, buf);
257                }
258                buf.push(106); // tail (nil)
259            }
260        }
261        Term::ImproperList(improper) => {
262            buf.push(108); // list
263            buf.extend_from_slice(&(improper.elements.len() as u32).to_be_bytes());
264            for element in &improper.elements {
265                encode_term_with_small_atoms(element, buf);
266            }
267            encode_term_with_small_atoms(&improper.last, buf); // tail
268        }
269        Term::Tuple(tuple) => {
270            if tuple.elements.len() <= 255 {
271                buf.push(104); // small_tuple
272                buf.push(tuple.elements.len() as u8);
273            } else {
274                buf.push(105); // large_tuple
275                buf.extend_from_slice(&(tuple.elements.len() as u32).to_be_bytes());
276            }
277            for element in &tuple.elements {
278                encode_term_with_small_atoms(element, buf);
279            }
280        }
281        Term::Map(map) => {
282            buf.push(116); // map
283            buf.extend_from_slice(&(map.map.len() as u32).to_be_bytes());
284            for (key, value) in &map.map {
285                encode_term_with_small_atoms(key, buf);
286                encode_term_with_small_atoms(value, buf);
287            }
288        }
289        Term::Pid(pid) => {
290            buf.push(103); // pid
291            encode_term_with_small_atoms(&Term::Atom(pid.node.clone()), buf);
292            buf.extend_from_slice(&pid.id.to_be_bytes());
293            buf.extend_from_slice(&pid.serial.to_be_bytes());
294            buf.push(pid.creation.try_into().unwrap());
295        }
296        Term::Port(port) => {
297            buf.push(102); // port
298            encode_term_with_small_atoms(&Term::Atom(port.node.clone()), buf);
299            buf.extend_from_slice(&port.id.to_be_bytes());
300            buf.push(port.creation.try_into().unwrap());
301        }
302        Term::Reference(reference) => {
303            buf.push(114); // new_reference
304            buf.extend_from_slice(&(reference.id.len() as u16).to_be_bytes());
305            encode_term_with_small_atoms(&Term::Atom(reference.node.clone()), buf);
306            buf.push(reference.creation.try_into().unwrap());
307            for id in &reference.id {
308                buf.extend_from_slice(&id.to_be_bytes());
309            }
310        }
311        Term::ExternalFun(ext_fun) => {
312            buf.push(113); // export
313            encode_term_with_small_atoms(&Term::Atom(ext_fun.module.clone()), buf);
314            encode_term_with_small_atoms(&Term::Atom(ext_fun.function.clone()), buf);
315            encode_term_with_small_atoms(&Term::FixInteger(eetf::FixInteger { value: ext_fun.arity as i32 }), buf);
316        }
317        Term::InternalFun(int_fun) => {
318            match int_fun.as_ref() {
319                eetf::InternalFun::Old { module, pid, free_vars, index, uniq } => {
320                    buf.push(117); // fun (old representation) 
321                    buf.extend_from_slice(&(*index as u32).to_be_bytes());
322                    buf.extend_from_slice(&(*uniq as u32).to_be_bytes());
323                    encode_term_with_small_atoms(&Term::Atom(module.clone()), buf);
324                    encode_term_with_small_atoms(&Term::Pid(pid.clone()), buf);
325                    for var in free_vars {
326                        encode_term_with_small_atoms(var, buf);
327                    }
328                }
329                eetf::InternalFun::New { module, arity, pid, free_vars, index, uniq, old_index, old_uniq } => {
330                    buf.push(112); // fun (new representation)
331                    buf.push(*arity);
332                    buf.extend_from_slice(uniq);
333                    buf.extend_from_slice(&index.to_be_bytes());
334                    buf.extend_from_slice(&(free_vars.len() as u32).to_be_bytes());
335                    encode_term_with_small_atoms(&Term::Atom(module.clone()), buf);
336                    encode_term_with_small_atoms(&Term::FixInteger(eetf::FixInteger { value: *old_index }), buf);
337                    encode_term_with_small_atoms(&Term::FixInteger(eetf::FixInteger { value: *old_uniq }), buf);
338                    encode_term_with_small_atoms(&Term::Pid(pid.clone()), buf);
339                    for var in free_vars {
340                        encode_term_with_small_atoms(var, buf);
341                    }
342                }
343            }
344        }
345        Term::BitBinary(bit_binary) => {
346            buf.push(77); // bit_binary
347            buf.extend_from_slice(&(bit_binary.bytes.len() as u32).to_be_bytes());
348            buf.push(bit_binary.tail_bits_size);
349            buf.extend_from_slice(&bit_binary.bytes);
350        }
351        Term::Float(float) => {
352            buf.push(70); // new_float
353            buf.extend_from_slice(&float.value.to_be_bytes());
354        }
355        Term::ByteList(byte_list) => {
356            buf.push(107); // string
357            buf.extend_from_slice(&(byte_list.bytes.len() as u16).to_be_bytes());
358            buf.extend_from_slice(&byte_list.bytes);
359        }
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366    use eetf::{Atom, FixInteger, Map};
367    use std::collections::HashMap;
368
369    #[test]
370    fn test_small_atom_encoding() {
371        let atom = Term::Atom(Atom::from("test"));
372        let encoded = encode_safe(&atom);
373
374        // Should start with ETF version (131) and small atom tag (119)
375        assert_eq!(encoded[0], 131); // ETF version
376        assert_eq!(encoded[1], 119); // small atom tag
377        assert_eq!(encoded[2], 4); // length of "test"
378        assert_eq!(&encoded[3..7], b"test");
379    }
380
381    #[test]
382    fn test_map_with_small_atoms() {
383        let mut map = HashMap::new();
384        map.insert(Term::Atom(Atom::from("key")), Term::Atom(Atom::from("value")));
385        let term_map = Term::Map(Map { map });
386
387        let encoded = encode_safe(&term_map);
388
389        // Should start with ETF version (131) and map tag (116)
390        assert_eq!(encoded[0], 131); // ETF version
391        assert_eq!(encoded[1], 116); // map tag
392
393        // Should contain small atom tags (119) for both key and value atoms
394        assert!(encoded.contains(&119)); // small atom tag should appear
395    }
396
397    #[test]
398    fn test_big_integer_encoding() {
399        use eetf::BigInteger;
400
401        // Test values that require BigInteger encoding
402        let test_values = vec![
403            2147483648u64, // i32::MAX + 1
404            4294967296u64, // u32::MAX + 1
405            1693958400u64, // Typical Unix timestamp
406        ];
407
408        for value in test_values {
409            let big_int_term = Term::BigInteger(BigInteger::from(value));
410
411            // Encode with original method
412            let mut original_encoded = Vec::new();
413            big_int_term.encode(&mut original_encoded).unwrap();
414
415            // Encode with our method
416            let our_encoded = encode_safe(&big_int_term);
417
418            // Both should produce identical bytes
419            assert_eq!(original_encoded, our_encoded, "Encoding mismatch for value {}", value);
420
421            // Both should decode to the same value
422            let original_decoded = Term::decode(&original_encoded[..]).unwrap();
423            let our_decoded = Term::decode(&our_encoded[..]).unwrap();
424
425            if let (Term::BigInteger(orig), Term::BigInteger(ours)) = (&original_decoded, &our_decoded) {
426                assert_eq!(orig.value, ours.value, "BigInteger values should match for {}", value);
427            }
428        }
429    }
430
431    #[test]
432    fn test_compatibility_with_original() {
433        // Test that our encoding produces the same structure as the original,
434        // except atoms use tag 119 instead of 100
435        let atom = Term::Atom(Atom::from("test"));
436        let mut original_encoded = Vec::new();
437        atom.encode(&mut original_encoded).unwrap();
438        let our_encoded = encode_safe(&atom);
439
440        println!("Original: {:?}", original_encoded);
441        println!("Our:      {:?}", our_encoded);
442
443        // Both should start with ETF version
444        assert_eq!(original_encoded[0], our_encoded[0]); // ETF version (131)
445
446        if original_encoded.len() == 8 && our_encoded.len() == 7 {
447            // Original uses legacy atom (100) with 2-byte length, ours uses small atom (119) with 1-byte length
448            assert_eq!(original_encoded[1], 100); // legacy atom  
449            assert_eq!(our_encoded[1], 119); // small atom
450
451            // For legacy atoms, the length is 2 bytes, for small atoms it's 1 byte
452            // original: [131, 100, 0, 4, 't', 'e', 's', 't']
453            // ours:     [131, 119, 4, 't', 'e', 's', 't']
454            assert_eq!(original_encoded[2], 0); // high byte of length (should be 0 for short strings)
455            assert_eq!(original_encoded[3], 4); // low byte of length
456            assert_eq!(our_encoded[2], 4); // single byte length
457
458            // String content should be the same
459            assert_eq!(original_encoded[4..], our_encoded[3..]);
460        } else {
461            // Fallback to original test logic if lengths are different than expected
462            assert_eq!(original_encoded.len(), our_encoded.len());
463            assert_eq!(original_encoded[1], 119); // legacy atom
464            assert_eq!(our_encoded[1], 119); // small atom
465            assert_eq!(original_encoded[2..], our_encoded[2..]);
466        }
467    }
468
469    #[test]
470    fn test_deterministic_encoding_mixed_key_types() {
471        // Test deterministic encoding with mixed key types following Erlang's hierarchy
472        let mut map_data = HashMap::new();
473
474        // Add keys in different order than they should be sorted
475        map_data.insert(Term::Atom(Atom::from("atom_key")), Term::FixInteger(FixInteger { value: 1 })); // Atoms (type 2)
476        map_data.insert(
477            Term::Binary(eetf::Binary { bytes: b"binary_key".to_vec() }),
478            Term::FixInteger(FixInteger { value: 2 }),
479        ); // Binaries (type 9)
480        map_data.insert(Term::FixInteger(FixInteger { value: 42 }), Term::FixInteger(FixInteger { value: 3 })); // Numbers (type 1)
481
482        let map = Term::Map(Map { map: map_data });
483
484        // Encode with deterministic ordering
485        let encoded = encode_safe_deterministic(&map);
486
487        // Verify it's properly encoded ETF
488        assert_eq!(encoded[0], 131); // ETF version
489        assert_eq!(encoded[1], 116); // map tag
490
491        // Should be decodable
492        let decoded = Term::decode(&encoded[..]).unwrap();
493        if let Term::Map(decoded_map) = decoded {
494            assert_eq!(decoded_map.map.len(), 3);
495
496            // Verify all keys are present
497            assert!(decoded_map.map.contains_key(&Term::FixInteger(FixInteger { value: 42 })));
498            assert!(decoded_map.map.contains_key(&Term::Atom(Atom::from("atom_key"))));
499            assert!(decoded_map.map.contains_key(&Term::Binary(eetf::Binary { bytes: b"binary_key".to_vec() })));
500        } else {
501            panic!("Decoded term is not a map");
502        }
503    }
504
505    #[test]
506    fn test_deterministic_encoding_atom_alphabetical_order() {
507        // Test that atoms are sorted alphabetically within their type
508        let mut map_data = HashMap::new();
509
510        // Add atom keys in reverse alphabetical order
511        map_data.insert(Term::Atom(Atom::from("zebra")), Term::FixInteger(FixInteger { value: 1 }));
512        map_data.insert(Term::Atom(Atom::from("apple")), Term::FixInteger(FixInteger { value: 2 }));
513        map_data.insert(Term::Atom(Atom::from("banana")), Term::FixInteger(FixInteger { value: 3 }));
514
515        let map = Term::Map(Map { map: map_data });
516
517        // Encode with deterministic ordering - should be consistent
518        let encoded1 = encode_safe_deterministic(&map);
519        let encoded2 = encode_safe_deterministic(&map);
520
521        // Multiple encodings should be identical (deterministic)
522        assert_eq!(encoded1, encoded2);
523
524        // Should be decodable
525        let decoded = Term::decode(&encoded1[..]).unwrap();
526        if let Term::Map(decoded_map) = decoded {
527            assert_eq!(decoded_map.map.len(), 3);
528        } else {
529            panic!("Decoded term is not a map");
530        }
531    }
532
533    #[test]
534    fn test_deterministic_encoding_number_ordering() {
535        // Test that numbers are ordered by value, not type
536        let mut map_data = HashMap::new();
537
538        // Add different number types
539        map_data.insert(Term::FixInteger(FixInteger { value: 100 }), Term::Atom(Atom::from("hundred")));
540        map_data.insert(Term::FixInteger(FixInteger { value: 5 }), Term::Atom(Atom::from("five")));
541        map_data.insert(Term::FixInteger(FixInteger { value: 50 }), Term::Atom(Atom::from("fifty")));
542
543        let map = Term::Map(Map { map: map_data });
544
545        let encoded = encode_safe_deterministic(&map);
546
547        // Should be decodable and deterministic
548        let decoded = Term::decode(&encoded[..]).unwrap();
549        if let Term::Map(decoded_map) = decoded {
550            assert_eq!(decoded_map.map.len(), 3);
551        } else {
552            panic!("Decoded term is not a map");
553        }
554    }
555
556    #[test]
557    fn test_deterministic_vs_original_compatibility() {
558        // Test that deterministic encoding uses small atoms like the original function
559        let atom = Term::Atom(Atom::from("test_atom"));
560
561        let deterministic_encoded = encode_safe_deterministic(&atom);
562        let small_atoms_encoded = encode_safe(&atom);
563
564        // Should be identical for simple atoms
565        assert_eq!(deterministic_encoded, small_atoms_encoded);
566
567        // Both should use small atom tag (119)
568        assert_eq!(deterministic_encoded[1], 119); // small atom tag
569        assert_eq!(small_atoms_encoded[1], 119); // small atom tag
570    }
571
572    #[test]
573    fn test_deterministic_encoding_anr_keys() {
574        // Test the specific ANR keys mentioned in the specification
575        let mut map_data = HashMap::new();
576
577        // Add ANR keys in original order
578        let anr_keys = ["ip4", "pk", "pop", "port", "signature", "ts", "version", "anr_name", "anr_desc"];
579        for (i, key) in anr_keys.iter().enumerate() {
580            map_data.insert(Term::Atom(Atom::from(*key)), Term::FixInteger(FixInteger { value: i as i32 }));
581        }
582
583        let map = Term::Map(Map { map: map_data });
584        let encoded = encode_safe_deterministic(&map);
585
586        // Should be deterministic across multiple calls
587        let encoded2 = encode_safe_deterministic(&map);
588        assert_eq!(encoded, encoded2);
589
590        // Should be decodable
591        let decoded = Term::decode(&encoded[..]).unwrap();
592        if let Term::Map(decoded_map) = decoded {
593            assert_eq!(decoded_map.map.len(), anr_keys.len());
594
595            // All keys should be present
596            for key in &anr_keys {
597                assert!(decoded_map.map.contains_key(&Term::Atom(Atom::from(*key))));
598            }
599        } else {
600            panic!("Decoded term is not a map");
601        }
602    }
603
604    #[test]
605    fn test_deterministic_encoding_nested_structures() {
606        // Test that nested maps and lists also get deterministic encoding
607        let mut inner_map = HashMap::new();
608        inner_map.insert(Term::Atom(Atom::from("z")), Term::FixInteger(FixInteger { value: 1 }));
609        inner_map.insert(Term::Atom(Atom::from("a")), Term::FixInteger(FixInteger { value: 2 }));
610
611        let mut outer_map = HashMap::new();
612        outer_map.insert(Term::Atom(Atom::from("nested")), Term::Map(Map { map: inner_map }));
613        outer_map.insert(
614            Term::Atom(Atom::from("list")),
615            Term::List(eetf::List {
616                elements: vec![Term::Atom(Atom::from("second")), Term::Atom(Atom::from("first"))],
617            }),
618        );
619
620        let map = Term::Map(Map { map: outer_map });
621
622        let encoded1 = encode_safe_deterministic(&map);
623        let encoded2 = encode_safe_deterministic(&map);
624
625        // Should be deterministic
626        assert_eq!(encoded1, encoded2);
627
628        // Should be decodable
629        let decoded = Term::decode(&encoded1[..]).unwrap();
630        if let Term::Map(_) = decoded {
631            // Successfully decoded
632        } else {
633            panic!("Decoded term is not a map");
634        }
635    }
636
637    #[test]
638    fn test_compare_terms_ordering() {
639        use super::compare_terms;
640
641        // Test type hierarchy: Numbers < Atoms < ... < Binaries
642        let number = Term::FixInteger(FixInteger { value: 42 });
643        let atom = Term::Atom(Atom::from("test"));
644        let binary = Term::Binary(eetf::Binary { bytes: b"test".to_vec() });
645
646        // Numbers should come before atoms
647        assert_eq!(compare_terms(&number, &atom), Ordering::Less);
648        assert_eq!(compare_terms(&atom, &number), Ordering::Greater);
649
650        // Atoms should come before binaries
651        assert_eq!(compare_terms(&atom, &binary), Ordering::Less);
652        assert_eq!(compare_terms(&binary, &atom), Ordering::Greater);
653
654        // Numbers should come before binaries
655        assert_eq!(compare_terms(&number, &binary), Ordering::Less);
656        assert_eq!(compare_terms(&binary, &number), Ordering::Greater);
657
658        // Same types should compare by value
659        let atom1 = Term::Atom(Atom::from("apple"));
660        let atom2 = Term::Atom(Atom::from("zebra"));
661        assert_eq!(compare_terms(&atom1, &atom2), Ordering::Less);
662        assert_eq!(compare_terms(&atom2, &atom1), Ordering::Greater);
663        assert_eq!(compare_terms(&atom1, &atom1), Ordering::Equal);
664    }
665
666    #[test]
667    fn test_deterministic_encoding_byte_order_verification() {
668        // Test that the actual byte encoding follows the correct order
669        let mut map_data = HashMap::new();
670
671        // Add keys in reverse order of how they should appear in encoding
672        map_data.insert(
673            Term::Binary(eetf::Binary { bytes: b"binary".to_vec() }),
674            Term::FixInteger(FixInteger { value: 3 }),
675        ); // Should be last (type 9)
676        map_data.insert(Term::Atom(Atom::from("zebra")), Term::FixInteger(FixInteger { value: 2 })); // Should be middle (type 2, but "zebra" comes after "apple")
677        map_data.insert(Term::Atom(Atom::from("apple")), Term::FixInteger(FixInteger { value: 1 })); // Should be second (type 2, "apple" comes first alphabetically)
678        map_data.insert(Term::FixInteger(FixInteger { value: 42 }), Term::FixInteger(FixInteger { value: 0 })); // Should be first (type 1)
679
680        let map = Term::Map(Map { map: map_data });
681        let encoded = encode_safe_deterministic(&map);
682
683        // Decode and extract the keys in their encoded order
684        let decoded = Term::decode(&encoded[..]).unwrap();
685        if let Term::Map(decoded_map) = decoded {
686            // Convert to Vec to check order (HashMap doesn't preserve order, but we can check the encoding bytes)
687            let mut found_keys = Vec::new();
688            for key in decoded_map.map.keys() {
689                found_keys.push(key.clone());
690            }
691
692            // We need to check the actual bytes to verify order since HashMap loses order
693            // Let's manually parse the encoded bytes to verify key ordering
694
695            // Skip ETF version (1 byte) + map tag (1 byte) + map size (4 bytes) = 6 bytes
696            let mut pos = 6;
697            let mut encoded_keys = Vec::new();
698
699            // Parse each key-value pair from the encoded bytes
700            for _ in 0..4 {
701                // We know we have 4 pairs
702                let key_start = pos;
703
704                // Parse the key to find where it ends
705                match encoded[pos] {
706                    119 => {
707                        // small atom
708                        let len = encoded[pos + 1] as usize;
709                        pos += 2 + len; // tag + length + atom bytes
710                    }
711                    109 => {
712                        // binary
713                        let len = u32::from_be_bytes([
714                            encoded[pos + 1],
715                            encoded[pos + 2],
716                            encoded[pos + 3],
717                            encoded[pos + 4],
718                        ]) as usize;
719                        pos += 5 + len; // tag + length (4 bytes) + binary bytes
720                    }
721                    97 => {
722                        // small integer
723                        pos += 2; // tag + value
724                    }
725                    98 => {
726                        // integer
727                        pos += 5; // tag + value (4 bytes)
728                    }
729                    _ => panic!("Unexpected key type in encoded data"),
730                }
731
732                let key_end = pos;
733                encoded_keys.push(&encoded[key_start..key_end]);
734
735                // Skip the value to get to next key
736                match encoded[pos] {
737                    97 => pos += 2, // small integer value
738                    98 => pos += 5, // integer value
739                    _ => panic!("Unexpected value type in encoded data"),
740                }
741            }
742
743            // Verify the keys appear in the correct order in the encoded bytes:
744            // 1. Number (42) - should be first
745            // 2. Atom "apple" - should be second
746            // 3. Atom "zebra" - should be third
747            // 4. Binary "binary" - should be fourth
748
749            // Check first key is the number 42
750            assert_eq!(encoded_keys[0][0], 97); // small integer tag
751            assert_eq!(encoded_keys[0][1], 42); // value 42
752
753            // Check second key is atom "apple"
754            assert_eq!(encoded_keys[1][0], 119); // small atom tag
755            assert_eq!(encoded_keys[1][1], 5); // length of "apple"
756            assert_eq!(&encoded_keys[1][2..7], b"apple");
757
758            // Check third key is atom "zebra"
759            assert_eq!(encoded_keys[2][0], 119); // small atom tag
760            assert_eq!(encoded_keys[2][1], 5); // length of "zebra"  
761            assert_eq!(&encoded_keys[2][2..7], b"zebra");
762
763            // Check fourth key is binary "binary"
764            assert_eq!(encoded_keys[3][0], 109); // binary tag
765            // Length is 4 bytes big-endian: [0, 0, 0, 6] for "binary"
766            assert_eq!(&encoded_keys[3][1..5], &[0, 0, 0, 6]);
767            assert_eq!(&encoded_keys[3][5..11], b"binary");
768        } else {
769            panic!("Decoded term is not a map");
770        }
771    }
772
773    #[test]
774    fn test_anr_keys_correct_alphabetical_order() {
775        // Test that ANR keys are encoded in correct alphabetical order as per spec
776        let mut map_data = HashMap::new();
777
778        // Add ANR keys in the original order (not alphabetical)
779        let anr_keys = ["ip4", "pk", "pop", "port", "signature", "ts", "version", "anr_name", "anr_desc"];
780        for (i, key) in anr_keys.iter().enumerate() {
781            map_data.insert(Term::Atom(Atom::from(*key)), Term::FixInteger(FixInteger { value: i as i32 }));
782        }
783
784        let map = Term::Map(Map { map: map_data });
785        let encoded = encode_safe_deterministic(&map);
786
787        // Parse the encoded bytes to extract keys in their actual encoded order
788        let mut pos = 6; // Skip ETF version + map tag + map size
789        let mut actual_key_order = Vec::new();
790
791        for _ in 0..anr_keys.len() {
792            // Parse atom key
793            if encoded[pos] == 119 {
794                // small atom tag
795                let len = encoded[pos + 1] as usize;
796                let atom_name = std::str::from_utf8(&encoded[pos + 2..pos + 2 + len]).unwrap();
797                actual_key_order.push(atom_name.to_string());
798                pos += 2 + len; // Skip key
799
800                // Skip value (small integer)
801                pos += 2; // tag + value
802            } else {
803                panic!("Expected atom key, found tag: {}", encoded[pos]);
804            }
805        }
806
807        // Expected order according to Erlang/Elixir alphabetical sorting
808        let expected_order = ["anr_desc", "anr_name", "ip4", "pk", "pop", "port", "signature", "ts", "version"];
809
810        assert_eq!(
811            actual_key_order, expected_order,
812            "ANR keys should be in alphabetical order: {:?}, but got: {:?}",
813            expected_order, actual_key_order
814        );
815    }
816
817    #[test]
818    fn test_mixed_types_correct_hierarchy_order() {
819        // Test that mixed types follow the exact Erlang hierarchy in encoded bytes
820        let mut map_data = HashMap::new();
821
822        // Add keys in reverse hierarchy order
823        map_data.insert(Term::Binary(eetf::Binary { bytes: b"bin".to_vec() }), Term::Atom(Atom::from("last"))); // Type 9 - should be last
824        map_data.insert(
825            Term::List(eetf::List { elements: vec![Term::Atom(Atom::from("item"))] }),
826            Term::Atom(Atom::from("eighth")),
827        ); // Type 8 - should be 4th
828        map_data.insert(
829            Term::Tuple(eetf::Tuple { elements: vec![Term::Atom(Atom::from("item"))] }),
830            Term::Atom(Atom::from("sixth")),
831        ); // Type 6 - should be 3rd  
832        map_data.insert(Term::Atom(Atom::from("atom")), Term::Atom(Atom::from("second"))); // Type 2 - should be 2nd
833        map_data.insert(Term::FixInteger(FixInteger { value: 123 }), Term::Atom(Atom::from("first"))); // Type 1 - should be 1st
834
835        let map = Term::Map(Map { map: map_data });
836        let encoded = encode_safe_deterministic(&map);
837
838        // Parse the encoded bytes to verify the key type ordering
839        let mut pos = 6; // Skip ETF version + map tag + map size
840        let mut actual_type_order = Vec::new();
841
842        for _ in 0..5 {
843            let key_tag = encoded[pos];
844            actual_type_order.push(key_tag);
845
846            // Skip the key based on its type
847            match key_tag {
848                97 => pos += 2, // small integer: tag + value
849                98 => pos += 5, // integer: tag + 4-byte value
850                119 => {
851                    // small atom: tag + length + atom bytes
852                    let len = encoded[pos + 1] as usize;
853                    pos += 2 + len;
854                }
855                104 => {
856                    // small tuple: tag + arity + elements
857                    let _arity = encoded[pos + 1] as usize;
858                    pos += 2; // tag + arity
859                    // Skip tuple elements (we know it's one atom)
860                    if encoded[pos] == 119 {
861                        // small atom
862                        let len = encoded[pos + 1] as usize;
863                        pos += 2 + len;
864                    }
865                }
866                108 => {
867                    // list: tag + length + elements + tail
868                    pos += 5; // tag + 4-byte length
869                    // Skip list elements (we know it's one atom)
870                    if encoded[pos] == 119 {
871                        // small atom
872                        let len = encoded[pos + 1] as usize;
873                        pos += 2 + len;
874                    }
875                    pos += 1; // nil tail
876                }
877                109 => {
878                    // binary: tag + 4-byte length + bytes
879                    let len =
880                        u32::from_be_bytes([encoded[pos + 1], encoded[pos + 2], encoded[pos + 3], encoded[pos + 4]])
881                            as usize;
882                    pos += 5 + len;
883                }
884                _ => panic!("Unexpected key type tag: {}", key_tag),
885            }
886
887            // Skip the value (all are atoms in this test)
888            if encoded[pos] == 119 {
889                // small atom
890                let len = encoded[pos + 1] as usize;
891                pos += 2 + len;
892            }
893        }
894
895        // Expected order: Number(97), Atom(119), Tuple(104), List(108), Binary(109)
896        let expected_tags = [97, 119, 104, 108, 109]; // small_int, small_atom, small_tuple, list, binary
897
898        assert_eq!(
899            actual_type_order, expected_tags,
900            "Key types should follow Erlang hierarchy: Numbers, Atoms, References, Ports, PIDs, Tuples, Maps, Lists, Binaries"
901        );
902    }
903
904    #[test]
905    fn test_elixir_deterministic_example_simple_map() {
906        // Test the exact example from DETERMINISTIC.md.local:
907        // map = %{z: 1, a: 2, m: 3}
908        // :erlang.term_to_binary(map, [:deterministic])
909        // <<131, 116, 0, 0, 0, 3, 119, 1, 97, 97, 2, 119, 1, 109, 97, 3, 119, 1, 122, 97, 1>>
910
911        let mut map_data = HashMap::new();
912        map_data.insert(Term::Atom(Atom::from("z")), Term::FixInteger(FixInteger { value: 1 }));
913        map_data.insert(Term::Atom(Atom::from("a")), Term::FixInteger(FixInteger { value: 2 }));
914        map_data.insert(Term::Atom(Atom::from("m")), Term::FixInteger(FixInteger { value: 3 }));
915
916        let map = Term::Map(Map { map: map_data });
917        let encoded = encode_safe_deterministic(&map);
918
919        // Expected bytes from Elixir's :erlang.term_to_binary(map, [:deterministic])
920        let expected: Vec<u8> = vec![
921            131, 116, 0, 0, 0, 3, // ETF version + map tag + size=3
922            119, 1, 97, 97, 2, // small_atom "a" -> small_int 2
923            119, 1, 109, 97, 3, // small_atom "m" -> small_int 3
924            119, 1, 122, 97, 1, // small_atom "z" -> small_int 1
925        ];
926
927        assert_eq!(
928            encoded, expected,
929            "Our encoding should match Elixir's deterministic encoding exactly.\nOur:      {:?}\nExpected: {:?}",
930            encoded, expected
931        );
932    }
933
934    #[test]
935    fn test_elixir_deterministic_example_mixed_types() {
936        // Test the exact example from DETERMINISTIC.md.local:
937        // mixed = %{:atom => 1, "string" => 2, 123 => 3}
938        // :erlang.term_to_binary(mixed, [:deterministic])
939        // <<131, 116, 0, 0, 0, 3, 97, 123, 97, 3, 119, 4, 97, 116, 111, 109, 97, 1, 109, 0, 0, 0, 6, 115, 116, 114, 105, 110, 103, 97, 2>>
940
941        let mut map_data = HashMap::new();
942        map_data.insert(Term::Atom(Atom::from("atom")), Term::FixInteger(FixInteger { value: 1 }));
943        map_data.insert(
944            Term::Binary(eetf::Binary { bytes: b"string".to_vec() }),
945            Term::FixInteger(FixInteger { value: 2 }),
946        );
947        map_data.insert(Term::FixInteger(FixInteger { value: 123 }), Term::FixInteger(FixInteger { value: 3 }));
948
949        let map = Term::Map(Map { map: map_data });
950        let encoded = encode_safe_deterministic(&map);
951
952        // Expected bytes from Elixir's :erlang.term_to_binary(mixed, [:deterministic])
953        let expected: Vec<u8> = vec![
954            131, 116, 0, 0, 0, 3, // ETF version + map tag + size=3
955            97, 123, 97, 3, // small_int 123 -> small_int 3
956            119, 4, 97, 116, 111, 109, 97, 1, // small_atom "atom" -> small_int 1
957            109, 0, 0, 0, 6, 115, 116, 114, 105, 110, 103, 97, 2, // binary "string" -> small_int 2
958        ];
959
960        assert_eq!(
961            encoded, expected,
962            "Our encoding should match Elixir's deterministic encoding exactly.\nOur:      {:?}\nExpected: {:?}",
963            encoded, expected
964        );
965    }
966
967    #[test]
968    fn test_decode_elixir_examples() {
969        // Verify that the Elixir examples can be decoded correctly by the eetf library
970
971        // Example 1: simple map
972        let elixir_simple: Vec<u8> =
973            vec![131, 116, 0, 0, 0, 3, 119, 1, 97, 97, 2, 119, 1, 109, 97, 3, 119, 1, 122, 97, 1];
974
975        let decoded_simple = Term::decode(&elixir_simple[..]).unwrap();
976        if let Term::Map(map) = decoded_simple {
977            assert_eq!(map.map.len(), 3);
978            assert_eq!(map.map.get(&Term::Atom(Atom::from("a"))), Some(&Term::FixInteger(FixInteger { value: 2 })));
979            assert_eq!(map.map.get(&Term::Atom(Atom::from("m"))), Some(&Term::FixInteger(FixInteger { value: 3 })));
980            assert_eq!(map.map.get(&Term::Atom(Atom::from("z"))), Some(&Term::FixInteger(FixInteger { value: 1 })));
981        } else {
982            panic!("Failed to decode simple map");
983        }
984
985        // Example 2: mixed types map
986        let elixir_mixed: Vec<u8> = vec![
987            131, 116, 0, 0, 0, 3, 97, 123, 97, 3, 119, 4, 97, 116, 111, 109, 97, 1, 109, 0, 0, 0, 6, 115, 116, 114,
988            105, 110, 103, 97, 2,
989        ];
990
991        let decoded_mixed = Term::decode(&elixir_mixed[..]).unwrap();
992        if let Term::Map(map) = decoded_mixed {
993            assert_eq!(map.map.len(), 3);
994            assert_eq!(
995                map.map.get(&Term::FixInteger(FixInteger { value: 123 })),
996                Some(&Term::FixInteger(FixInteger { value: 3 }))
997            );
998            assert_eq!(map.map.get(&Term::Atom(Atom::from("atom"))), Some(&Term::FixInteger(FixInteger { value: 1 })));
999            assert_eq!(
1000                map.map.get(&Term::Binary(eetf::Binary { bytes: b"string".to_vec() })),
1001                Some(&Term::FixInteger(FixInteger { value: 2 }))
1002            );
1003        } else {
1004            panic!("Failed to decode mixed types map");
1005        }
1006    }
1007
1008    #[test]
1009    fn test_comprehensive_data_cases_1_to_10() {
1010        // Test 1: %{m: 3, a: 1, z: 2}
1011        let mut map1 = HashMap::new();
1012        map1.insert(Term::Atom(Atom::from("m")), Term::FixInteger(FixInteger { value: 3 }));
1013        map1.insert(Term::Atom(Atom::from("a")), Term::FixInteger(FixInteger { value: 1 }));
1014        map1.insert(Term::Atom(Atom::from("z")), Term::FixInteger(FixInteger { value: 2 }));
1015        let term1 = Term::Map(Map { map: map1 });
1016        let expected1 = vec![131, 116, 0, 0, 0, 3, 119, 1, 97, 97, 1, 119, 1, 109, 97, 3, 119, 1, 122, 97, 2];
1017        assert_eq!(encode_safe_deterministic(&term1), expected1, "Test 1 failed");
1018
1019        // Test 2: %{123 => 3, 45.67 => 4, :atom => 1, "string" => 2}
1020        let mut map2 = HashMap::new();
1021        map2.insert(Term::FixInteger(FixInteger { value: 123 }), Term::FixInteger(FixInteger { value: 3 }));
1022        map2.insert(Term::Float(eetf::Float { value: 45.67 }), Term::FixInteger(FixInteger { value: 4 }));
1023        map2.insert(Term::Atom(Atom::from("atom")), Term::FixInteger(FixInteger { value: 1 }));
1024        map2.insert(
1025            Term::Binary(eetf::Binary { bytes: b"string".to_vec() }),
1026            Term::FixInteger(FixInteger { value: 2 }),
1027        );
1028        let term2 = Term::Map(Map { map: map2 });
1029        let expected2 = vec![
1030            131, 116, 0, 0, 0, 4, 97, 123, 97, 3, 70, 64, 70, 213, 194, 143, 92, 40, 246, 97, 4, 119, 4, 97, 116, 111,
1031            109, 97, 1, 109, 0, 0, 0, 6, 115, 116, 114, 105, 110, 103, 97, 2,
1032        ];
1033        assert_eq!(encode_safe_deterministic(&term2), expected2, "Test 2 failed");
1034
1035        // Test 3: %{outer: %{inner: %{deep: :value}}, top: :level}
1036        let mut inner_inner = HashMap::new();
1037        inner_inner.insert(Term::Atom(Atom::from("deep")), Term::Atom(Atom::from("value")));
1038        let mut inner = HashMap::new();
1039        inner.insert(Term::Atom(Atom::from("inner")), Term::Map(Map { map: inner_inner }));
1040        let mut map3 = HashMap::new();
1041        map3.insert(Term::Atom(Atom::from("outer")), Term::Map(Map { map: inner }));
1042        map3.insert(Term::Atom(Atom::from("top")), Term::Atom(Atom::from("level")));
1043        let term3 = Term::Map(Map { map: map3 });
1044        let expected3 = vec![
1045            131, 116, 0, 0, 0, 2, 119, 5, 111, 117, 116, 101, 114, 116, 0, 0, 0, 1, 119, 5, 105, 110, 110, 101, 114,
1046            116, 0, 0, 0, 1, 119, 4, 100, 101, 101, 112, 119, 5, 118, 97, 108, 117, 101, 119, 3, 116, 111, 112, 119, 5,
1047            108, 101, 118, 101, 108,
1048        ];
1049        assert_eq!(encode_safe_deterministic(&term3), expected3, "Test 3 failed");
1050
1051        // Test 4: [1, :atom, "string", [nested: :list], %{map: :inside}]
1052        let nested_map = {
1053            let mut m = HashMap::new();
1054            m.insert(Term::Atom(Atom::from("map")), Term::Atom(Atom::from("inside")));
1055            Term::Map(Map { map: m })
1056        };
1057        let term4 = Term::List(eetf::List {
1058            elements: vec![
1059                Term::FixInteger(FixInteger { value: 1 }),
1060                Term::Atom(Atom::from("atom")),
1061                Term::Binary(eetf::Binary { bytes: b"string".to_vec() }),
1062                Term::List(eetf::List {
1063                    elements: vec![Term::Tuple(eetf::Tuple {
1064                        elements: vec![Term::Atom(Atom::from("nested")), Term::Atom(Atom::from("list"))],
1065                    })],
1066                }),
1067                nested_map,
1068            ],
1069        });
1070        let expected4 = vec![
1071            131, 108, 0, 0, 0, 5, 97, 1, 119, 4, 97, 116, 111, 109, 109, 0, 0, 0, 6, 115, 116, 114, 105, 110, 103, 108,
1072            0, 0, 0, 1, 104, 2, 119, 6, 110, 101, 115, 116, 101, 100, 119, 4, 108, 105, 115, 116, 106, 116, 0, 0, 0, 1,
1073            119, 3, 109, 97, 112, 119, 6, 105, 110, 115, 105, 100, 101, 106,
1074        ];
1075        assert_eq!(encode_safe_deterministic(&term4), expected4, "Test 4 failed");
1076
1077        // Test 5: {:simple, :tuple, 123, "mixed"}
1078        let term5 = Term::Tuple(eetf::Tuple {
1079            elements: vec![
1080                Term::Atom(Atom::from("simple")),
1081                Term::Atom(Atom::from("tuple")),
1082                Term::FixInteger(FixInteger { value: 123 }),
1083                Term::Binary(eetf::Binary { bytes: b"mixed".to_vec() }),
1084            ],
1085        });
1086        let expected5 = vec![
1087            131, 104, 4, 119, 6, 115, 105, 109, 112, 108, 101, 119, 5, 116, 117, 112, 108, 101, 97, 123, 109, 0, 0, 0,
1088            5, 109, 105, 120, 101, 100,
1089        ];
1090        assert_eq!(encode_safe_deterministic(&term5), expected5, "Test 5 failed");
1091
1092        // Test 6: %{"apple" => :a, "monkey" => :m, "zebra" => :z}
1093        let mut map6 = HashMap::new();
1094        map6.insert(Term::Binary(eetf::Binary { bytes: b"apple".to_vec() }), Term::Atom(Atom::from("a")));
1095        map6.insert(Term::Binary(eetf::Binary { bytes: b"monkey".to_vec() }), Term::Atom(Atom::from("m")));
1096        map6.insert(Term::Binary(eetf::Binary { bytes: b"zebra".to_vec() }), Term::Atom(Atom::from("z")));
1097        let term6 = Term::Map(Map { map: map6 });
1098        let expected6 = vec![
1099            131, 116, 0, 0, 0, 3, 109, 0, 0, 0, 5, 97, 112, 112, 108, 101, 119, 1, 97, 109, 0, 0, 0, 6, 109, 111, 110,
1100            107, 101, 121, 119, 1, 109, 109, 0, 0, 0, 5, 122, 101, 98, 114, 97, 119, 1, 122,
1101        ];
1102        assert_eq!(encode_safe_deterministic(&term6), expected6, "Test 6 failed");
1103
1104        // Test 7: %{-5 => :negative, 1 => :one, 999 => :big, 2.5 => :two_half}
1105        let mut map7 = HashMap::new();
1106        map7.insert(Term::FixInteger(FixInteger { value: -5 }), Term::Atom(Atom::from("negative")));
1107        map7.insert(Term::FixInteger(FixInteger { value: 1 }), Term::Atom(Atom::from("one")));
1108        map7.insert(Term::FixInteger(FixInteger { value: 999 }), Term::Atom(Atom::from("big")));
1109        map7.insert(Term::Float(eetf::Float { value: 2.5 }), Term::Atom(Atom::from("two_half")));
1110        let term7 = Term::Map(Map { map: map7 });
1111        let expected7 = vec![
1112            131, 116, 0, 0, 0, 4, 98, 255, 255, 255, 251, 119, 8, 110, 101, 103, 97, 116, 105, 118, 101, 97, 1, 119, 3,
1113            111, 110, 101, 98, 0, 0, 3, 231, 119, 3, 98, 105, 103, 70, 64, 4, 0, 0, 0, 0, 0, 0, 119, 8, 116, 119, 111,
1114            95, 104, 97, 108, 102,
1115        ];
1116        assert_eq!(encode_safe_deterministic(&term7), expected7, "Test 7 failed");
1117
1118        // Test 8: Complex nested structure (simplified)
1119        let mut config_map = HashMap::new();
1120        config_map.insert(Term::Atom(Atom::from("debug")), Term::Atom(Atom::from("true")));
1121        config_map.insert(Term::Atom(Atom::from("timeout")), Term::FixInteger(FixInteger { value: 5000 }));
1122
1123        let mut user1 = HashMap::new();
1124        user1.insert(Term::Atom(Atom::from("id")), Term::FixInteger(FixInteger { value: 1 }));
1125        user1.insert(Term::Atom(Atom::from("name")), Term::Binary(eetf::Binary { bytes: b"Alice".to_vec() }));
1126        user1.insert(
1127            Term::Atom(Atom::from("roles")),
1128            Term::List(eetf::List { elements: vec![Term::Atom(Atom::from("admin")), Term::Atom(Atom::from("user"))] }),
1129        );
1130
1131        let mut user2 = HashMap::new();
1132        user2.insert(Term::Atom(Atom::from("id")), Term::FixInteger(FixInteger { value: 2 }));
1133        user2.insert(Term::Atom(Atom::from("name")), Term::Binary(eetf::Binary { bytes: b"Bob".to_vec() }));
1134        user2.insert(
1135            Term::Atom(Atom::from("roles")),
1136            Term::List(eetf::List { elements: vec![Term::Atom(Atom::from("user"))] }),
1137        );
1138
1139        let mut map8 = HashMap::new();
1140        map8.insert(Term::Atom(Atom::from("config")), Term::Map(Map { map: config_map }));
1141        map8.insert(
1142            Term::Atom(Atom::from("users")),
1143            Term::List(eetf::List { elements: vec![Term::Map(Map { map: user1 }), Term::Map(Map { map: user2 })] }),
1144        );
1145        let term8 = Term::Map(Map { map: map8 });
1146        let expected8 = vec![
1147            131, 116, 0, 0, 0, 2, 119, 6, 99, 111, 110, 102, 105, 103, 116, 0, 0, 0, 2, 119, 5, 100, 101, 98, 117, 103,
1148            119, 4, 116, 114, 117, 101, 119, 7, 116, 105, 109, 101, 111, 117, 116, 98, 0, 0, 19, 136, 119, 5, 117, 115,
1149            101, 114, 115, 108, 0, 0, 0, 2, 116, 0, 0, 0, 3, 119, 2, 105, 100, 97, 1, 119, 4, 110, 97, 109, 101, 109,
1150            0, 0, 0, 5, 65, 108, 105, 99, 101, 119, 5, 114, 111, 108, 101, 115, 108, 0, 0, 0, 2, 119, 5, 97, 100, 109,
1151            105, 110, 119, 4, 117, 115, 101, 114, 106, 116, 0, 0, 0, 3, 119, 2, 105, 100, 97, 2, 119, 4, 110, 97, 109,
1152            101, 109, 0, 0, 0, 3, 66, 111, 98, 119, 5, 114, 111, 108, 101, 115, 108, 0, 0, 0, 1, 119, 4, 117, 115, 101,
1153            114, 106, 106,
1154        ];
1155        assert_eq!(encode_safe_deterministic(&term8), expected8, "Test 8 failed");
1156
1157        // Test 9: %{1 => %{"nested" => %{deep: %{4 => :very_deep}}}, :top => "level"}
1158        let mut deepest = HashMap::new();
1159        deepest.insert(Term::FixInteger(FixInteger { value: 4 }), Term::Atom(Atom::from("very_deep")));
1160        let mut deep_map = HashMap::new();
1161        deep_map.insert(Term::Atom(Atom::from("deep")), Term::Map(Map { map: deepest }));
1162        let mut nested_map = HashMap::new();
1163        nested_map.insert(Term::Binary(eetf::Binary { bytes: b"nested".to_vec() }), Term::Map(Map { map: deep_map }));
1164        let mut map9 = HashMap::new();
1165        map9.insert(Term::FixInteger(FixInteger { value: 1 }), Term::Map(Map { map: nested_map }));
1166        map9.insert(Term::Atom(Atom::from("top")), Term::Binary(eetf::Binary { bytes: b"level".to_vec() }));
1167        let term9 = Term::Map(Map { map: map9 });
1168        let expected9 = vec![
1169            131, 116, 0, 0, 0, 2, 97, 1, 116, 0, 0, 0, 1, 109, 0, 0, 0, 6, 110, 101, 115, 116, 101, 100, 116, 0, 0, 0,
1170            1, 119, 4, 100, 101, 101, 112, 116, 0, 0, 0, 1, 97, 4, 119, 9, 118, 101, 114, 121, 95, 100, 101, 101, 112,
1171            119, 3, 116, 111, 112, 109, 0, 0, 0, 5, 108, 101, 118, 101, 108,
1172        ];
1173        assert_eq!(encode_safe_deterministic(&term9), expected9, "Test 9 failed");
1174
1175        // Test 10: [{:name, "John"}, {:age, 30}, {:city, "NYC"}, {1, :number_key}]
1176        let term10 = Term::List(eetf::List {
1177            elements: vec![
1178                Term::Tuple(eetf::Tuple {
1179                    elements: vec![
1180                        Term::Atom(Atom::from("name")),
1181                        Term::Binary(eetf::Binary { bytes: b"John".to_vec() }),
1182                    ],
1183                }),
1184                Term::Tuple(eetf::Tuple {
1185                    elements: vec![Term::Atom(Atom::from("age")), Term::FixInteger(FixInteger { value: 30 })],
1186                }),
1187                Term::Tuple(eetf::Tuple {
1188                    elements: vec![
1189                        Term::Atom(Atom::from("city")),
1190                        Term::Binary(eetf::Binary { bytes: b"NYC".to_vec() }),
1191                    ],
1192                }),
1193                Term::Tuple(eetf::Tuple {
1194                    elements: vec![Term::FixInteger(FixInteger { value: 1 }), Term::Atom(Atom::from("number_key"))],
1195                }),
1196            ],
1197        });
1198        let expected10 = vec![
1199            131, 108, 0, 0, 0, 4, 104, 2, 119, 4, 110, 97, 109, 101, 109, 0, 0, 0, 4, 74, 111, 104, 110, 104, 2, 119,
1200            3, 97, 103, 101, 97, 30, 104, 2, 119, 4, 99, 105, 116, 121, 109, 0, 0, 0, 3, 78, 89, 67, 104, 2, 97, 1,
1201            119, 10, 110, 117, 109, 98, 101, 114, 95, 107, 101, 121, 106,
1202        ];
1203        assert_eq!(encode_safe_deterministic(&term10), expected10, "Test 10 failed");
1204    }
1205
1206    #[test]
1207    fn test_comprehensive_data_cases_special_selection() {
1208        // Test 23: ANR-like structure - critical for this project
1209        let mut map23 = HashMap::new();
1210        map23.insert(Term::Atom(Atom::from("port")), Term::FixInteger(FixInteger { value: 36969 }));
1211        map23.insert(Term::Atom(Atom::from("version")), Term::Binary(eetf::Binary { bytes: b"1.1.5".to_vec() }));
1212        map23.insert(Term::Atom(Atom::from("signature")), Term::Binary(eetf::Binary { bytes: vec![13, 14, 15, 16] }));
1213        map23.insert(Term::Atom(Atom::from("pop")), Term::Binary(eetf::Binary { bytes: vec![9, 10, 11, 12] }));
1214        map23.insert(Term::Atom(Atom::from("ip4")), Term::Binary(eetf::Binary { bytes: b"192.168.1.1".to_vec() }));
1215        map23.insert(Term::Atom(Atom::from("ts")), Term::FixInteger(FixInteger { value: 1640995200 }));
1216        map23.insert(Term::Atom(Atom::from("pk")), Term::Binary(eetf::Binary { bytes: vec![1, 2, 3, 4, 5, 6, 7, 8] }));
1217        map23.insert(Term::Atom(Atom::from("anr_name")), Term::Binary(eetf::Binary { bytes: b"test_node".to_vec() }));
1218        map23.insert(
1219            Term::Atom(Atom::from("anr_desc")),
1220            Term::Binary(eetf::Binary { bytes: b"Test description".to_vec() }),
1221        );
1222        let term23 = Term::Map(Map { map: map23 });
1223        let expected23 = vec![
1224            131, 116, 0, 0, 0, 9, 119, 8, 97, 110, 114, 95, 100, 101, 115, 99, 109, 0, 0, 0, 16, 84, 101, 115, 116, 32,
1225            100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 119, 8, 97, 110, 114, 95, 110, 97, 109, 101, 109, 0,
1226            0, 0, 9, 116, 101, 115, 116, 95, 110, 111, 100, 101, 119, 3, 105, 112, 52, 109, 0, 0, 0, 11, 49, 57, 50,
1227            46, 49, 54, 56, 46, 49, 46, 49, 119, 2, 112, 107, 109, 0, 0, 0, 8, 1, 2, 3, 4, 5, 6, 7, 8, 119, 3, 112,
1228            111, 112, 109, 0, 0, 0, 4, 9, 10, 11, 12, 119, 4, 112, 111, 114, 116, 98, 0, 0, 144, 105, 119, 9, 115, 105,
1229            103, 110, 97, 116, 117, 114, 101, 109, 0, 0, 0, 4, 13, 14, 15, 16, 119, 2, 116, 115, 98, 97, 207, 153, 128,
1230            119, 7, 118, 101, 114, 115, 105, 111, 110, 109, 0, 0, 0, 5, 49, 46, 49, 46, 53,
1231        ];
1232        assert_eq!(encode_safe_deterministic(&term23), expected23, "Test 23 (ANR) failed");
1233
1234        // Test 11: Maps with tuple keys
1235        let mut map11 = HashMap::new();
1236        map11.insert(Term::Atom(Atom::from("simple")), Term::Atom(Atom::from("value3")));
1237        map11.insert(
1238            Term::Tuple(eetf::Tuple {
1239                elements: vec![Term::Atom(Atom::from("another")), Term::Atom(Atom::from("compound"))],
1240            }),
1241            Term::Atom(Atom::from("value2")),
1242        );
1243        map11.insert(
1244            Term::Tuple(eetf::Tuple {
1245                elements: vec![Term::Atom(Atom::from("compound")), Term::Atom(Atom::from("key"))],
1246            }),
1247            Term::Atom(Atom::from("value1")),
1248        );
1249        let term11 = Term::Map(Map { map: map11 });
1250        let expected11 = vec![
1251            131, 116, 0, 0, 0, 3, 119, 6, 115, 105, 109, 112, 108, 101, 119, 6, 118, 97, 108, 117, 101, 51, 104, 2,
1252            119, 7, 97, 110, 111, 116, 104, 101, 114, 119, 8, 99, 111, 109, 112, 111, 117, 110, 100, 119, 6, 118, 97,
1253            108, 117, 101, 50, 104, 2, 119, 8, 99, 111, 109, 112, 111, 117, 110, 100, 119, 3, 107, 101, 121, 119, 6,
1254            118, 97, 108, 117, 101, 49,
1255        ];
1256        assert_eq!(encode_safe_deterministic(&term11), expected11, "Test 11 failed");
1257
1258        // Test 13: Simple list - order shouldn't change (lists aren't sorted internally)
1259        let term13 = Term::List(eetf::List {
1260            elements: vec![
1261                Term::Atom(Atom::from("zebra")),
1262                Term::Atom(Atom::from("alpha")),
1263                Term::Atom(Atom::from("beta")),
1264                Term::Atom(Atom::from("gamma")),
1265                Term::Atom(Atom::from("omega")),
1266            ],
1267        });
1268        let expected13 = vec![
1269            131, 108, 0, 0, 0, 5, 119, 5, 122, 101, 98, 114, 97, 119, 5, 97, 108, 112, 104, 97, 119, 4, 98, 101, 116,
1270            97, 119, 5, 103, 97, 109, 109, 97, 119, 5, 111, 109, 101, 103, 97, 106,
1271        ];
1272        assert_eq!(encode_safe_deterministic(&term13), expected13, "Test 13 failed");
1273
1274        // Test 21: Number ordering verification
1275        let mut map21 = HashMap::new();
1276        map21.insert(Term::FixInteger(FixInteger { value: 1 }), Term::Atom(Atom::from("one")));
1277        map21.insert(Term::FixInteger(FixInteger { value: 500 }), Term::Atom(Atom::from("five_hundred")));
1278        map21.insert(Term::FixInteger(FixInteger { value: 99999 }), Term::Atom(Atom::from("almost_hundred_k")));
1279        map21.insert(Term::FixInteger(FixInteger { value: 1000000 }), Term::Atom(Atom::from("million")));
1280        let term21 = Term::Map(Map { map: map21 });
1281        let expected21 = vec![
1282            131, 116, 0, 0, 0, 4, 97, 1, 119, 3, 111, 110, 101, 98, 0, 0, 1, 244, 119, 12, 102, 105, 118, 101, 95, 104,
1283            117, 110, 100, 114, 101, 100, 98, 0, 1, 134, 159, 119, 16, 97, 108, 109, 111, 115, 116, 95, 104, 117, 110,
1284            100, 114, 101, 100, 95, 107, 98, 0, 15, 66, 64, 119, 7, 109, 105, 108, 108, 105, 111, 110,
1285        ];
1286        assert_eq!(encode_safe_deterministic(&term21), expected21, "Test 21 failed");
1287
1288        // Test 29: Negative numbers and zero ordering
1289        let mut map29 = HashMap::new();
1290        map29.insert(Term::FixInteger(FixInteger { value: -1000 }), Term::Atom(Atom::from("neg_thousand")));
1291        map29.insert(Term::FixInteger(FixInteger { value: -1 }), Term::Atom(Atom::from("neg_one")));
1292        map29.insert(Term::FixInteger(FixInteger { value: 0 }), Term::Atom(Atom::from("zero")));
1293        map29.insert(Term::Float(eetf::Float { value: 0.0 }), Term::Atom(Atom::from("float_zero")));
1294        let term29 = Term::Map(Map { map: map29 });
1295        let expected29 = vec![
1296            131, 116, 0, 0, 0, 4, 98, 255, 255, 252, 24, 119, 12, 110, 101, 103, 95, 116, 104, 111, 117, 115, 97, 110,
1297            100, 98, 255, 255, 255, 255, 119, 7, 110, 101, 103, 95, 111, 110, 101, 97, 0, 119, 4, 122, 101, 114, 111,
1298            70, 0, 0, 0, 0, 0, 0, 0, 0, 119, 10, 102, 108, 111, 97, 116, 95, 122, 101, 114, 111,
1299        ];
1300        assert_eq!(encode_safe_deterministic(&term29), expected29, "Test 29 failed");
1301    }
1302
1303    #[test]
1304    fn test_comprehensive_data_byte_list_cases() {
1305        // Test 14: Mixed data types in map
1306        let mut map14 = HashMap::new();
1307        map14.insert(Term::Atom(Atom::from("binary")), Term::Binary(eetf::Binary { bytes: vec![1, 2, 3] }));
1308        map14.insert(Term::Atom(Atom::from("list")), Term::ByteList(eetf::ByteList { bytes: vec![1, 2, 3] }));
1309        map14.insert(Term::Atom(Atom::from("map")), {
1310            let mut inner = HashMap::new();
1311            inner.insert(Term::Atom(Atom::from("a")), Term::FixInteger(FixInteger { value: 1 }));
1312            inner.insert(Term::Atom(Atom::from("b")), Term::FixInteger(FixInteger { value: 2 }));
1313            Term::Map(Map { map: inner })
1314        });
1315        map14.insert(
1316            Term::Atom(Atom::from("tuple")),
1317            Term::Tuple(eetf::Tuple {
1318                elements: vec![
1319                    Term::FixInteger(FixInteger { value: 1 }),
1320                    Term::FixInteger(FixInteger { value: 2 }),
1321                    Term::FixInteger(FixInteger { value: 3 }),
1322                ],
1323            }),
1324        );
1325        let term14 = Term::Map(Map { map: map14 });
1326        let expected14 = vec![
1327            131, 116, 0, 0, 0, 4, 119, 6, 98, 105, 110, 97, 114, 121, 109, 0, 0, 0, 3, 1, 2, 3, 119, 4, 108, 105, 115,
1328            116, 107, 0, 3, 1, 2, 3, 119, 3, 109, 97, 112, 116, 0, 0, 0, 2, 119, 1, 97, 97, 1, 119, 1, 98, 97, 2, 119,
1329            5, 116, 117, 112, 108, 101, 104, 3, 97, 1, 97, 2, 97, 3,
1330        ];
1331        assert_eq!(encode_safe_deterministic(&term14), expected14, "Test 14 failed");
1332
1333        // Test 34: Charlists and strings
1334        let mut map34 = HashMap::new();
1335        map34.insert(Term::Atom(Atom::from("string")), Term::Binary(eetf::Binary { bytes: b"hello".to_vec() }));
1336        map34.insert(Term::Atom(Atom::from("charlist")), Term::ByteList(eetf::ByteList { bytes: b"hello".to_vec() }));
1337        map34.insert(Term::Atom(Atom::from("mixed_list")), Term::ByteList(eetf::ByteList { bytes: b"Hello".to_vec() }));
1338        let term34 = Term::Map(Map { map: map34 });
1339        let expected34 = vec![
1340            131, 116, 0, 0, 0, 3, 119, 8, 99, 104, 97, 114, 108, 105, 115, 116, 107, 0, 5, 104, 101, 108, 108, 111,
1341            119, 10, 109, 105, 120, 101, 100, 95, 108, 105, 115, 116, 107, 0, 5, 72, 101, 108, 108, 111, 119, 6, 115,
1342            116, 114, 105, 110, 103, 109, 0, 0, 0, 5, 104, 101, 108, 108, 111,
1343        ];
1344        assert_eq!(encode_safe_deterministic(&term34), expected34, "Test 34 failed");
1345    }
1346
1347    #[test]
1348    fn test_large_integers_elixir_compatibility() {
1349        use eetf::BigInteger;
1350
1351        let very_small = Term::BigInteger(BigInteger::from(214u64));
1352        let encoded_very_small = encode_safe(&very_small);
1353        println!("{:?}", encoded_very_small);
1354
1355        // Test 1: 2147483648 (1 << 31, just over i32::MAX)
1356        // Expected from Elixir: <<131, 110, 4, 0, 0, 0, 0, 128>>
1357        let small = Term::BigInteger(BigInteger::from(2147483648u64));
1358        let encoded_small = encode_safe(&small);
1359        let expected_small = vec![131, 110, 4, 0, 0, 0, 0, 128];
1360        assert_eq!(
1361            encoded_small, expected_small,
1362            "Encoding mismatch for 2147483648\nOur:      {:?}\nExpected: {:?}",
1363            encoded_small, expected_small
1364        );
1365
1366        // Test 2: 4294967296 (1 << 32, just over u32::MAX)
1367        // Expected from Elixir: <<131, 110, 5, 0, 0, 0, 0, 0, 1>>
1368        let edge = Term::BigInteger(BigInteger::from(4294967296u64));
1369        let encoded_edge = encode_safe(&edge);
1370        let expected_edge = vec![131, 110, 5, 0, 0, 0, 0, 0, 1];
1371        assert_eq!(
1372            encoded_edge, expected_edge,
1373            "Encoding mismatch for 4294967296\nOur:      {:?}\nExpected: {:?}",
1374            encoded_edge, expected_edge
1375        );
1376
1377        // Test 3: 8589934592 (1 << 33)
1378        // Expected from Elixir: <<131, 110, 5, 0, 0, 0, 0, 0, 2>>
1379        let over = Term::BigInteger(BigInteger::from(8589934592u64));
1380        let encoded_over = encode_safe(&over);
1381        let expected_over = vec![131, 110, 5, 0, 0, 0, 0, 0, 2];
1382        assert_eq!(
1383            encoded_over, expected_over,
1384            "Encoding mismatch for 8589934592\nOur:      {:?}\nExpected: {:?}",
1385            encoded_over, expected_over
1386        );
1387
1388        // Verify all can be decoded back to the correct values
1389        let decoded_small = Term::decode(&encoded_small[..]).unwrap();
1390        if let Term::BigInteger(val) = decoded_small {
1391            assert_eq!(val.value, BigInteger::from(2147483648u64).value);
1392        } else {
1393            panic!("Failed to decode 2147483648 as BigInteger");
1394        }
1395
1396        let decoded_edge = Term::decode(&encoded_edge[..]).unwrap();
1397        if let Term::BigInteger(val) = decoded_edge {
1398            assert_eq!(val.value, BigInteger::from(4294967296u64).value);
1399        } else {
1400            panic!("Failed to decode 4294967296 as BigInteger");
1401        }
1402
1403        let decoded_over = Term::decode(&encoded_over[..]).unwrap();
1404        if let Term::BigInteger(val) = decoded_over {
1405            assert_eq!(val.value, BigInteger::from(8589934592u64).value);
1406        } else {
1407            panic!("Failed to decode 8589934592 as BigInteger");
1408        }
1409
1410        // Test 4: Map with large integer and binary containing ETF-encoded large integer
1411        // Elixir: m = %{b: <<131, 110, 5, 0, 0, 0, 0, 0, 2>>, a: 8589934592}
1412        // Expected: <<131, 116, 0, 0, 0, 2, 119, 1, 97, 110, 5, 0, 0, 0, 0, 0, 2, 119, 1, 98, 109, 0, 0, 0, 9, 131, 110, 5, 0, 0, 0, 0, 0, 2>>
1413        let mut map = HashMap::new();
1414        map.insert(Term::Atom(Atom::from("a")), Term::BigInteger(BigInteger::from(8589934592u64)));
1415        map.insert(
1416            Term::Atom(Atom::from("b")),
1417            Term::Binary(eetf::Binary { bytes: vec![131, 110, 5, 0, 0, 0, 0, 0, 2] }),
1418        );
1419        let map_term = Term::Map(Map { map });
1420        let encoded_map = encode_safe_deterministic(&map_term);
1421        let expected_map = vec![
1422            131, 116, 0, 0, 0, 2, // ETF version + map tag + size=2
1423            119, 1, 97, 110, 5, 0, 0, 0, 0, 0, 2, // atom "a" -> big int 8589934592
1424            119, 1, 98, 109, 0, 0, 0, 9, 131, 110, 5, 0, 0, 0, 0, 0, 2, // atom "b" -> binary containing ETF bytes
1425        ];
1426        assert_eq!(
1427            encoded_map, expected_map,
1428            "Encoding mismatch for map with large integer and binary\nOur:      {:?}\nExpected: {:?}",
1429            encoded_map, expected_map
1430        );
1431
1432        // Verify the map can be decoded back correctly
1433        let decoded_map = Term::decode(&encoded_map[..]).unwrap();
1434        if let Term::Map(decoded) = decoded_map {
1435            assert_eq!(decoded.map.len(), 2);
1436
1437            // Check the large integer value
1438            if let Some(Term::BigInteger(val)) = decoded.map.get(&Term::Atom(Atom::from("a"))) {
1439                assert_eq!(val.value, BigInteger::from(8589934592u64).value);
1440            } else {
1441                panic!("Failed to find or decode key 'a' as BigInteger");
1442            }
1443
1444            // Check the binary value
1445            if let Some(Term::Binary(bin)) = decoded.map.get(&Term::Atom(Atom::from("b"))) {
1446                assert_eq!(bin.bytes, vec![131, 110, 5, 0, 0, 0, 0, 0, 2]);
1447            } else {
1448                panic!("Failed to find or decode key 'b' as Binary");
1449            }
1450        } else {
1451            panic!("Failed to decode map");
1452        }
1453    }
1454}