erlang_term/
dump.rs

1use crate::consts::*;
2use crate::RawTerm;
3use num_bigint::{BigInt, Sign};
4
5#[cfg(feature = "zlib")]
6use flate2::read::ZlibEncoder;
7#[cfg(feature = "zlib")]
8use flate2::Compression;
9#[cfg(feature = "zlib")]
10use std::io::prelude::*;
11
12pub fn to_bytes(raw: RawTerm) -> Vec<u8> {
13    internal_to_binary(raw, true)
14}
15
16#[cfg(feature = "zlib")]
17pub fn to_gzip_bytes(raw: RawTerm, level: Compression) -> std::io::Result<Vec<u8>> {
18    let bytes = internal_to_binary(raw, false);
19    let mut buffer = Vec::with_capacity(bytes.len());
20    let mut encoder = ZlibEncoder::new(&bytes[..], level);
21    push_prefix(&mut buffer);
22    buffer.push(ZLIB);
23    let length = bytes.len() as u32;
24    buffer.extend_from_slice(&length.to_be_bytes());
25    encoder.read_to_end(&mut buffer)?;
26    Ok(buffer)
27}
28
29pub fn internal_to_binary(raw: RawTerm, add_prefix: bool) -> Vec<u8> {
30    use RawTerm::*;
31    match raw {
32        Atom(x) => atom(x, add_prefix),
33        SmallAtom(x) => small_atom(x, add_prefix),
34        AtomDeprecated(x) => atom_deprecated(x, add_prefix),
35        SmallAtomDeprecated(x) => small_atom_deprecated(x, add_prefix),
36        Float(x) => float(*x, add_prefix),
37        Nil => nil(add_prefix),
38        SmallInt(x) => small_int(x, add_prefix),
39        Int(x) => int(x, add_prefix),
40        String(x) => string(x, add_prefix),
41        Binary(x) => binary(x, add_prefix),
42        BitBinary { binary, bit, bits } => bitbinary(binary, bit, bits, add_prefix),
43        SmallBigInt(x) => small_big_int(x, add_prefix),
44        LargeBigInt(x) => large_big_int(x, add_prefix),
45        SmallTuple(x) => small_tuple(x, add_prefix),
46        LargeTuple(x) => large_tuple(x, add_prefix),
47        List(x) => list(x, add_prefix),
48        Map(x) => map(x, add_prefix),
49        Port { node, id, creation } => port(*node, id, creation, add_prefix),
50        NewPort { node, id, creation } => new_port(*node, id, creation, add_prefix),
51        Ref { node, id, creation } => reference(*node, id, creation, add_prefix),
52        NewerRef { node, id, creation } => newer_reference(*node, id, creation, add_prefix),
53        Pid {
54            node,
55            id,
56            serial,
57            creation,
58        } => pid(*node, id, serial, creation, add_prefix),
59        NewPid {
60            node,
61            id,
62            serial,
63            creation,
64        } => new_pid(*node, id, serial, creation, add_prefix),
65        Function {
66            size,
67            arity,
68            uniq,
69            index,
70            module,
71            old_index,
72            old_uniq,
73            pid,
74            free_var,
75        } => function(
76            size, arity, uniq, index, *module, *old_index, *old_uniq, *pid, free_var, add_prefix,
77        ),
78        Improper(_) => unreachable!(),
79    }
80}
81
82fn insert_prefix(bytes: &mut Vec<u8>) {
83    bytes.insert(0, REVISION);
84}
85
86fn push_prefix(bytes: &mut Vec<u8>) {
87    bytes.push(REVISION);
88}
89
90fn small_atom(raw: String, add_prefix: bool) -> Vec<u8> {
91    let mut bytes = raw.into_bytes();
92    let length = bytes.len() as u8;
93    bytes.insert(0, length);
94    bytes.insert(0, SMALL_ATOM_UTF8_EXT);
95    if add_prefix {
96        insert_prefix(&mut bytes)
97    };
98    bytes
99}
100
101fn atom(raw: String, add_prefix: bool) -> Vec<u8> {
102    let bytes = raw.into_bytes();
103    let length = bytes.len();
104    let mut buffer = Vec::with_capacity(length + 4);
105
106    if add_prefix {
107        push_prefix(&mut buffer)
108    };
109    buffer.push(ATOM_UTF8_EXT);
110    buffer.extend((length as u16).to_be_bytes());
111    buffer.extend(bytes);
112    buffer
113}
114
115fn small_atom_deprecated(raw: String, add_prefix: bool) -> Vec<u8> {
116    let mut bytes = raw.into_bytes();
117    let length = bytes.len() as u8;
118    bytes.insert(0, length);
119    bytes.insert(0, SMALL_ATOM_EXT_DEPRECATED);
120    if add_prefix {
121        insert_prefix(&mut bytes)
122    };
123    bytes
124}
125
126fn atom_deprecated(raw: String, add_prefix: bool) -> Vec<u8> {
127    let bytes = raw.into_bytes();
128    let length = bytes.len();
129    let mut buffer = Vec::with_capacity(length + 4);
130
131    if add_prefix {
132        push_prefix(&mut buffer)
133    };
134    buffer.push(ATOM_EXT_DEPRECATED);
135    buffer.extend((length as u16).to_be_bytes());
136    buffer.extend(bytes);
137    buffer
138}
139
140fn float(raw: f64, add_prefix: bool) -> Vec<u8> {
141    let mut buffer = Vec::with_capacity(10);
142
143    if add_prefix {
144        push_prefix(&mut buffer)
145    };
146    buffer.push(NEW_FLOAT_EXT);
147    buffer.extend(raw.to_be_bytes());
148    buffer
149}
150
151fn nil(add_prefix: bool) -> Vec<u8> {
152    if add_prefix {
153        vec![REVISION, NIL_EXT]
154    } else {
155        vec![NIL_EXT]
156    }
157}
158
159fn small_int(raw: u8, add_prefix: bool) -> Vec<u8> {
160    if add_prefix {
161        vec![REVISION, SMALL_INTEGER_EXT, raw]
162    } else {
163        vec![SMALL_INTEGER_EXT, raw]
164    }
165}
166
167fn int(raw: i32, add_prefix: bool) -> Vec<u8> {
168    let mut buffer = Vec::with_capacity(6);
169
170    if add_prefix {
171        push_prefix(&mut buffer)
172    };
173    buffer.push(INTEGER_EXT);
174    buffer.extend(raw.to_be_bytes());
175    buffer
176}
177
178fn string(mut raw: Vec<u8>, add_prefix: bool) -> Vec<u8> {
179    let length = raw.len();
180    let mut buffer = Vec::with_capacity(length + 4);
181
182    if add_prefix {
183        push_prefix(&mut buffer)
184    };
185    buffer.push(STRING_EXT);
186    buffer.extend((length as u16).to_be_bytes());
187    buffer.append(&mut raw);
188    buffer
189}
190
191fn binary(mut raw: Vec<u8>, add_prefix: bool) -> Vec<u8> {
192    let length = raw.len();
193    let mut buffer = Vec::with_capacity(length + 6);
194
195    if add_prefix {
196        push_prefix(&mut buffer)
197    };
198    buffer.push(BINARY_EXT);
199    buffer.extend((length as u32).to_be_bytes());
200    buffer.append(&mut raw);
201    buffer
202}
203
204fn bitbinary(mut binary: Vec<u8>, bit: u8, bits: u8, add_prefix: bool) -> Vec<u8> {
205    let length = binary.len();
206    let mut buffer = Vec::with_capacity(length + 7);
207
208    if add_prefix {
209        push_prefix(&mut buffer)
210    };
211    buffer.push(BIT_BINARY_EXT);
212    buffer.extend(((length as u32) + 1).to_be_bytes());
213    buffer.push(bits);
214    buffer.append(&mut binary);
215    // do some magic here
216    buffer.push(bit << (8u8.saturating_sub(bits)));
217    buffer
218}
219
220fn small_big_int(raw: BigInt, add_prefix: bool) -> Vec<u8> {
221    let (sign, mut bytes) = raw.to_bytes_le();
222    let sign = sign_to_byte(sign);
223
224    let mut buffer = Vec::with_capacity(bytes.len() + 4);
225
226    if add_prefix {
227        push_prefix(&mut buffer)
228    };
229    buffer.push(SMALL_BIG_EXT);
230    buffer.push(bytes.len() as u8);
231    buffer.push(sign);
232    buffer.append(&mut bytes);
233    buffer
234}
235
236fn large_big_int(raw: BigInt, add_prefix: bool) -> Vec<u8> {
237    let (sign, mut bytes) = raw.to_bytes_le();
238    let sign = sign_to_byte(sign);
239    let length = bytes.len();
240
241    let mut buffer = Vec::with_capacity(length + 7);
242
243    if add_prefix {
244        push_prefix(&mut buffer)
245    };
246    buffer.push(LARGE_BIG_EXT);
247    buffer.extend((length as u32).to_be_bytes());
248    buffer.push(sign);
249    buffer.append(&mut bytes);
250    buffer
251}
252
253fn small_tuple(raw: Vec<RawTerm>, add_prefix: bool) -> Vec<u8> {
254    let arity = raw.len();
255    let mut bytes: Vec<u8> = raw
256        .into_iter()
257        .flat_map(|x| internal_to_binary(x, false))
258        .collect();
259
260    let mut buffer = Vec::with_capacity(bytes.len() + 3);
261
262    if add_prefix {
263        push_prefix(&mut buffer)
264    };
265    buffer.push(SMALL_TUPLE_EXT);
266    buffer.push(arity as u8);
267    buffer.append(&mut bytes);
268    buffer
269}
270
271fn large_tuple(raw: Vec<RawTerm>, add_prefix: bool) -> Vec<u8> {
272    let arity = raw.len();
273    let mut bytes: Vec<u8> = raw
274        .into_iter()
275        .flat_map(|x| internal_to_binary(x, false))
276        .collect();
277
278    let mut buffer = Vec::with_capacity(bytes.len() + 6);
279
280    if add_prefix {
281        push_prefix(&mut buffer)
282    };
283    buffer.push(LARGE_TUPLE_EXT);
284    buffer.extend((arity as u32).to_be_bytes());
285    buffer.append(&mut bytes);
286    buffer
287}
288
289fn list(mut raw: Vec<RawTerm>, add_prefix: bool) -> Vec<u8> {
290    let tail = raw.pop();
291    let tail = if let Some(RawTerm::Improper(x)) = tail {
292        vec![*x]
293    } else if let Some(x) = tail {
294        vec![x, RawTerm::Nil]
295    } else {
296        vec![RawTerm::Nil]
297    };
298
299    raw.extend(tail);
300    let arity = raw.len() - 1;
301    let mut bytes: Vec<u8> = raw
302        .into_iter()
303        .flat_map(|x| internal_to_binary(x, false))
304        .collect();
305
306    let mut buffer = Vec::with_capacity(bytes.len() + 6);
307    if add_prefix {
308        push_prefix(&mut buffer)
309    };
310    buffer.push(LIST_EXT);
311    buffer.extend((arity as u32).to_be_bytes());
312    buffer.append(&mut bytes);
313    buffer
314}
315
316fn map(raw: Vec<(RawTerm, RawTerm)>, add_prefix: bool) -> Vec<u8> {
317    let arity = raw.len();
318    let mut bytes: Vec<u8> = raw
319        .into_iter()
320        .flat_map(|(a, b)| {
321            internal_to_binary(a, false)
322                .into_iter()
323                .chain(internal_to_binary(b, false))
324        })
325        .collect();
326
327    let mut buffer = Vec::with_capacity(bytes.len() + 6);
328
329    if add_prefix {
330        push_prefix(&mut buffer)
331    };
332    buffer.push(MAP_EXT);
333    buffer.extend((arity as u32).to_be_bytes());
334    buffer.append(&mut bytes);
335    buffer
336}
337
338fn port(node: RawTerm, id: u32, creation: u8, add_prefix: bool) -> Vec<u8> {
339    let node_binary = internal_to_binary(node, false);
340
341    let mut buffer = Vec::with_capacity(node_binary.len() + 7);
342
343    if add_prefix {
344        push_prefix(&mut buffer)
345    };
346    buffer.push(PORT_EXT);
347    buffer.extend(node_binary);
348    buffer.extend(id.to_be_bytes());
349    buffer.push(creation);
350    buffer
351}
352
353fn new_port(node: RawTerm, id: u32, creation: u32, add_prefix: bool) -> Vec<u8> {
354    let node_binary = internal_to_binary(node, false);
355
356    let mut buffer = Vec::with_capacity(node_binary.len() + 7);
357
358    if add_prefix {
359        push_prefix(&mut buffer)
360    };
361    buffer.push(NEW_PORT_EXT);
362    buffer.extend(node_binary);
363    buffer.extend(id.to_be_bytes());
364    buffer.extend(creation.to_be_bytes());
365    buffer
366}
367
368fn reference(node: RawTerm, id: Vec<u32>, creation: u8, add_prefix: bool) -> Vec<u8> {
369    let id_length = id.len();
370    let node_binary = internal_to_binary(node, false);
371    let mut id_bytes: Vec<u8> = Vec::new();
372    for part in id {
373        id_bytes.extend(part.to_be_bytes());
374    }
375
376    let mut buffer = Vec::with_capacity(node_binary.len() + id_bytes.len() + 5);
377
378    if add_prefix {
379        push_prefix(&mut buffer)
380    };
381    buffer.push(NEW_REFERENCE_EXT);
382    buffer.extend((id_length as u16).to_be_bytes());
383    buffer.extend(node_binary);
384    buffer.extend(creation.to_be_bytes());
385    buffer.extend(id_bytes);
386    buffer
387}
388
389fn newer_reference(node: RawTerm, id: Vec<u32>, creation: u32, add_prefix: bool) -> Vec<u8> {
390    let id_length = id.len();
391    let node_binary = internal_to_binary(node, false);
392    let mut id_bytes: Vec<u8> = Vec::new();
393    for part in id {
394        id_bytes.extend(part.to_be_bytes());
395    }
396
397    let mut buffer = Vec::with_capacity(node_binary.len() + id_bytes.len() + 5);
398
399    if add_prefix {
400        push_prefix(&mut buffer)
401    };
402    buffer.push(NEWER_REFERENCE_EXT);
403    buffer.extend((id_length as u16).to_be_bytes());
404    buffer.extend(node_binary);
405    buffer.extend(creation.to_be_bytes());
406    buffer.extend(id_bytes);
407    buffer
408}
409
410fn pid(node: RawTerm, id: u32, serial: u32, creation: u8, add_prefix: bool) -> Vec<u8> {
411    let node_binary = internal_to_binary(node, false);
412
413    let mut buffer = Vec::with_capacity(node_binary.len() + 11);
414
415    if add_prefix {
416        push_prefix(&mut buffer)
417    };
418    buffer.push(PID_EXT);
419    buffer.extend(node_binary);
420    buffer.extend(id.to_be_bytes());
421    buffer.extend(serial.to_be_bytes());
422    buffer.push(creation);
423    buffer
424}
425fn new_pid(node: RawTerm, id: u32, serial: u32, creation: u32, add_prefix: bool) -> Vec<u8> {
426    let node_binary = internal_to_binary(node, false);
427
428    let mut buffer = Vec::with_capacity(node_binary.len() + 11);
429
430    if add_prefix {
431        push_prefix(&mut buffer)
432    };
433    buffer.push(NEW_PID_EXT);
434    buffer.extend(node_binary);
435    buffer.extend(id.to_be_bytes());
436    buffer.extend(serial.to_be_bytes());
437    buffer.extend(creation.to_be_bytes());
438    buffer
439}
440fn function(
441    size: u32,
442    arity: u8,
443    uniq: [u8; 16],
444    index: u32,
445    module: RawTerm,
446    old_index: RawTerm,
447    old_uniq: RawTerm,
448    pid: RawTerm,
449    free_var: Vec<RawTerm>,
450    add_prefix: bool,
451) -> Vec<u8> {
452    let free_var_length = free_var.len();
453    let module_binary = internal_to_binary(module, false);
454    let pid_binary = internal_to_binary(pid, false);
455    let old_index = internal_to_binary(old_index, false);
456    let old_uniq = internal_to_binary(old_uniq, false);
457    let free_var_bytes: Vec<u8> = free_var
458        .into_iter()
459        .flat_map(|x| internal_to_binary(x, false))
460        .collect();
461
462    let mut buffer =
463        Vec::with_capacity(module_binary.len() + pid_binary.len() + free_var_bytes.len() + 31);
464    if add_prefix {
465        push_prefix(&mut buffer)
466    };
467    buffer.push(NEW_FUN_EXT);
468    buffer.extend(size.to_be_bytes());
469    buffer.push(arity);
470    buffer.extend(uniq);
471    buffer.extend(index.to_be_bytes());
472    buffer.extend((free_var_length as u32).to_be_bytes());
473    buffer.extend(module_binary);
474    buffer.extend(old_index);
475    buffer.extend(old_uniq);
476    buffer.extend(pid_binary);
477    buffer.extend(free_var_bytes);
478    buffer
479}
480
481fn sign_to_byte(sign: Sign) -> u8 {
482    match sign {
483        Sign::Minus => 1,
484        _ => 0,
485    }
486}
487
488#[cfg(test)]
489mod binary_tests {
490    use crate::consts::REVISION;
491    use crate::{read_binary, to_bytes, RawTerm};
492    use num_bigint::{BigInt, BigUint};
493
494    #[test]
495    fn small_atom() {
496        let out = to_bytes(RawTerm::SmallAtom("test".to_string()));
497        assert_eq!(out, vec![REVISION, 119, 4, 116, 101, 115, 116])
498    }
499
500    #[test]
501    fn atom() {
502        let out = to_bytes(RawTerm::Atom("test".to_string()));
503        assert_eq!(out, vec![REVISION, 118, 0, 4, 116, 101, 115, 116])
504    }
505
506    #[test]
507    fn small_atom_deprecated() {
508        let out = to_bytes(RawTerm::SmallAtomDeprecated("test".to_string()));
509        assert_eq!(out, vec![REVISION, 115, 4, 116, 101, 115, 116])
510    }
511
512    #[test]
513    fn atom_deprecated() {
514        let out = to_bytes(RawTerm::AtomDeprecated("test".to_string()));
515        assert_eq!(out, vec![REVISION, 100, 0, 4, 116, 101, 115, 116])
516    }
517
518    #[test]
519    fn float() {
520        let out = to_bytes(RawTerm::Float(3.14.into()));
521        assert_eq!(out, vec![REVISION, 70, 64, 9, 30, 184, 81, 235, 133, 31])
522    }
523
524    #[test]
525    fn nil() {
526        let out = to_bytes(RawTerm::Nil);
527        assert_eq!(out, vec![REVISION, 106])
528    }
529
530    #[test]
531    fn small_int() {
532        let out = to_bytes(RawTerm::SmallInt(4));
533        assert_eq!(out, vec![REVISION, 97, 4])
534    }
535
536    #[test]
537    fn int() {
538        let out = to_bytes(RawTerm::Int(-13));
539        assert_eq!(out, vec![REVISION, 98, 255, 255, 255, 243]);
540
541        let out = to_bytes(RawTerm::Int(12345));
542        assert_eq!(out, vec![REVISION, 98, 0, 0, 48, 57])
543    }
544
545    #[test]
546    fn string() {
547        let out = to_bytes(RawTerm::String(b"testing".to_vec()));
548        assert_eq!(
549            out,
550            vec![REVISION, 107, 0, 7, 116, 101, 115, 116, 105, 110, 103]
551        )
552    }
553
554    #[test]
555    fn binary() {
556        let out = to_bytes(RawTerm::Binary(b"testing".to_vec()));
557        assert_eq!(
558            out,
559            vec![REVISION, 109, 0, 0, 0, 7, 116, 101, 115, 116, 105, 110, 103]
560        )
561    }
562
563    #[test]
564    fn bitbinary() {
565        let out = to_bytes(RawTerm::BitBinary {
566            binary: b"testing".to_vec(),
567            bit: 13,
568            bits: 4,
569        });
570        assert_eq!(
571            out,
572            vec![REVISION, 77, 0, 0, 0, 8, 4, 116, 101, 115, 116, 105, 110, 103, 208]
573        );
574
575        let out = to_bytes(RawTerm::BitBinary {
576            binary: vec![95],
577            bit: 23,
578            bits: 5,
579        });
580        assert_eq!(out, vec![REVISION, 77, 0, 0, 0, 2, 5, 95, 184]);
581    }
582
583    #[test]
584    fn small_big_int() {
585        let out = to_bytes(RawTerm::SmallBigInt(
586            BigInt::parse_bytes(b"123456789123456789123456789", 10).unwrap(),
587        ));
588        assert_eq!(
589            out,
590            vec![REVISION, 110, 11, 0, 21, 95, 4, 124, 159, 177, 227, 242, 253, 30, 102]
591        )
592    }
593
594    #[test]
595    fn large_big_int() {
596        use num_traits::pow::Pow;
597
598        let expected = read_binary("bins/large_big_int.bin").unwrap();
599        let nineninenine = BigUint::parse_bytes(b"999", 10).unwrap();
600        let out = to_bytes(RawTerm::LargeBigInt(BigInt::from(
601            nineninenine.clone().pow(&nineninenine),
602        )));
603
604        assert_eq!(expected, out);
605    }
606
607    #[test]
608    fn small_tuple() {
609        let out = to_bytes(RawTerm::SmallTuple(vec![
610            RawTerm::String(b"testing".to_vec()),
611            RawTerm::SmallInt(1),
612        ]));
613
614        assert_eq!(
615            out,
616            vec![REVISION, 104, 2, 107, 0, 7, 116, 101, 115, 116, 105, 110, 103, 97, 1]
617        )
618    }
619
620    #[test]
621    fn large_tuple() {
622        let out = to_bytes(RawTerm::LargeTuple(vec![
623            RawTerm::String(b"testing".to_vec()),
624            RawTerm::SmallInt(1),
625        ]));
626
627        assert_eq!(
628            out,
629            vec![REVISION, 105, 0, 0, 0, 2, 107, 0, 7, 116, 101, 115, 116, 105, 110, 103, 97, 1]
630        )
631    }
632
633    #[test]
634    fn list() {
635        let out = to_bytes(RawTerm::List(vec![RawTerm::String(b"testing".to_vec())]));
636
637        assert_eq!(
638            out,
639            vec![REVISION, 108, 0, 0, 0, 1, 107, 0, 7, 116, 101, 115, 116, 105, 110, 103, 106]
640        )
641    }
642
643    #[test]
644    fn improper_list() {
645        let out = to_bytes(RawTerm::List(vec![
646            RawTerm::String(b"testing".to_vec()),
647            RawTerm::Improper(Box::new(RawTerm::SmallInt(3))),
648        ]));
649
650        assert_eq!(
651            out,
652            vec![REVISION, 108, 0, 0, 0, 1, 107, 0, 7, 116, 101, 115, 116, 105, 110, 103, 97, 3]
653        )
654    }
655
656    #[test]
657    fn atom_map() {
658        let out = to_bytes(RawTerm::Map(
659            vec![
660                (
661                    RawTerm::AtomDeprecated("other".to_string()),
662                    RawTerm::Binary(b"test".to_vec()),
663                ),
664                (
665                    RawTerm::AtomDeprecated("some".to_string()),
666                    RawTerm::SmallInt(3),
667                ),
668            ]
669            .into_iter()
670            .collect(),
671        ));
672
673        assert_eq!(
674            out,
675            vec![
676                REVISION, 116, 0, 0, 0, 2, 100, 0, 5, 111, 116, 104, 101, 114, 109, 0, 0, 0, 4,
677                116, 101, 115, 116, 100, 0, 4, 115, 111, 109, 101, 97, 3
678            ]
679        )
680    }
681
682    #[test]
683    fn map() {
684        use RawTerm::*;
685        let map = vec![
686            (SmallInt(1), Binary(b"one".to_vec())),
687            (
688                List(vec![Binary(b"list as a key".to_vec())]),
689                List(vec![
690                    Binary(b"another".to_vec()),
691                    Map(vec![(
692                        AtomDeprecated("test".to_string()),
693                        AtomDeprecated("false".to_string()),
694                    )]
695                    .into_iter()
696                    .collect()),
697                ]),
698            ),
699            (Binary(b"float".to_vec()), Float(3.14.into())),
700            (
701                Binary(b"large".to_vec()),
702                SmallBigInt(BigInt::parse_bytes(b"123456789123456789", 10).unwrap()),
703            ),
704            (
705                Binary(b"nested".to_vec()),
706                Map(vec![(Binary(b"ok".to_vec()), Nil)].into_iter().collect()),
707            ),
708            (
709                AtomDeprecated("tuple".to_string()),
710                SmallTuple(vec![SmallInt(1), AtomDeprecated("more".to_string())]),
711            ),
712        ]
713        .into_iter()
714        .collect();
715
716        let out = to_bytes(RawTerm::Map(map));
717
718        assert_eq!(
719            out,
720            vec![
721                REVISION, 116, 0, 0, 0, 6, 97, 1, 109, 0, 0, 0, 3, 111, 110, 101, 108, 0, 0, 0, 1,
722                109, 0, 0, 0, 13, 108, 105, 115, 116, 32, 97, 115, 32, 97, 32, 107, 101, 121, 106,
723                108, 0, 0, 0, 2, 109, 0, 0, 0, 7, 97, 110, 111, 116, 104, 101, 114, 116, 0, 0, 0,
724                1, 100, 0, 4, 116, 101, 115, 116, 100, 0, 5, 102, 97, 108, 115, 101, 106, 109, 0,
725                0, 0, 5, 102, 108, 111, 97, 116, 70, 64, 9, 30, 184, 81, 235, 133, 31, 109, 0, 0,
726                0, 5, 108, 97, 114, 103, 101, 110, 8, 0, 21, 95, 208, 172, 75, 155, 182, 1, 109, 0,
727                0, 0, 6, 110, 101, 115, 116, 101, 100, 116, 0, 0, 0, 1, 109, 0, 0, 0, 2, 111, 107,
728                106, 100, 0, 5, 116, 117, 112, 108, 101, 104, 2, 97, 1, 100, 0, 4, 109, 111, 114,
729                101
730            ]
731        );
732    }
733
734    #[test]
735    fn port() {
736        let out = to_bytes(RawTerm::Port {
737            node: Box::new(RawTerm::SmallAtom("something@something".to_string())),
738            id: 123,
739            creation: 2,
740        });
741
742        assert_eq!(
743            out,
744            vec![
745                REVISION, 102, 119, 19, 115, 111, 109, 101, 116, 104, 105, 110, 103, 64, 115, 111,
746                109, 101, 116, 104, 105, 110, 103, 0, 0, 0, 123, 2
747            ]
748        )
749    }
750
751    #[test]
752    fn new_port() {
753        let out = to_bytes(RawTerm::NewPort {
754            node: Box::new(RawTerm::SmallAtom("something@something".to_string())),
755            id: 123,
756            creation: 2,
757        });
758
759        assert_eq!(
760            out,
761            vec![
762                REVISION, 89, 119, 19, 115, 111, 109, 101, 116, 104, 105, 110, 103, 64, 115, 111,
763                109, 101, 116, 104, 105, 110, 103, 0, 0, 0, 123, 0, 0, 0, 2
764            ]
765        )
766    }
767
768    #[test]
769    fn reference() {
770        let out = to_bytes(RawTerm::Ref {
771            node: Box::new(RawTerm::AtomDeprecated("something@something".to_string())),
772            id: vec![158726, 438566918, 237133],
773            creation: 2,
774        });
775
776        assert_eq!(
777            out,
778            vec![
779                REVISION, 114, 0, 3, 100, 0, 19, 115, 111, 109, 101, 116, 104, 105, 110, 103, 64,
780                115, 111, 109, 101, 116, 104, 105, 110, 103, 2, 0, 2, 108, 6, 26, 36, 0, 6, 0, 3,
781                158, 77
782            ]
783        )
784    }
785
786    #[test]
787    fn newer_reference() {
788        let out = to_bytes(RawTerm::NewerRef {
789            node: Box::new(RawTerm::AtomDeprecated("something@something".to_string())),
790            id: vec![158726, 438566918, 237133],
791            creation: 2,
792        });
793
794        assert_eq!(
795            out,
796            vec![
797                REVISION, 90, 0, 3, 100, 0, 19, 115, 111, 109, 101, 116, 104, 105, 110, 103, 64,
798                115, 111, 109, 101, 116, 104, 105, 110, 103, 0, 0, 0, 2, 0, 2, 108, 6, 26, 36, 0,
799                6, 0, 3, 158, 77
800            ]
801        )
802    }
803
804    #[test]
805    fn pid() {
806        let out = to_bytes(RawTerm::Pid {
807            node: Box::new(RawTerm::SmallAtom("something@something".to_string())),
808            id: 123,
809            serial: 654,
810            creation: 2,
811        });
812
813        assert_eq!(
814            out,
815            vec![
816                REVISION, 103, 119, 19, 115, 111, 109, 101, 116, 104, 105, 110, 103, 64, 115, 111,
817                109, 101, 116, 104, 105, 110, 103, 0, 0, 0, 123, 0, 0, 2, 142, 2
818            ]
819        )
820    }
821
822    #[test]
823    fn function() {
824        let input = RawTerm::Function {
825            size: 134,
826            arity: 0,
827            uniq: [
828                241, 72, 50, 109, 70, 84, 198, 45, 20, 94, 42, 25, 184, 243, 5, 100,
829            ],
830            index: 21,
831            module: Box::new(RawTerm::AtomDeprecated("erl_eval".to_string())),
832            old_index: Box::new(RawTerm::SmallInt(21)),
833            old_uniq: Box::new(RawTerm::Int(126501267)),
834            pid: Box::new(RawTerm::Pid {
835                node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
836                id: 102,
837                serial: 0,
838                creation: 0,
839            }),
840            free_var: vec![RawTerm::SmallTuple(vec![
841                RawTerm::Nil,
842                RawTerm::AtomDeprecated("none".to_string()),
843                RawTerm::AtomDeprecated("none".to_string()),
844                RawTerm::List(vec![RawTerm::SmallTuple(vec![
845                    RawTerm::AtomDeprecated("clause".to_string()),
846                    RawTerm::SmallInt(3),
847                    RawTerm::Nil,
848                    RawTerm::Nil,
849                    RawTerm::List(vec![RawTerm::SmallTuple(vec![
850                        RawTerm::AtomDeprecated("atom".to_string()),
851                        RawTerm::SmallInt(0),
852                        RawTerm::AtomDeprecated("nil".to_string()),
853                    ])]),
854                ])]),
855            ])],
856        };
857        let out = to_bytes(input);
858
859        assert_eq!(
860            out,
861            vec![
862                REVISION, 112, 0, 0, 0, 134, 0, 241, 72, 50, 109, 70, 84, 198, 45, 20, 94, 42, 25,
863                184, 243, 5, 100, 0, 0, 0, 21, 0, 0, 0, 1, 100, 0, 8, 101, 114, 108, 95, 101, 118,
864                97, 108, 97, 21, 98, 7, 138, 65, 147, 103, 100, 0, 13, 110, 111, 110, 111, 100,
865                101, 64, 110, 111, 104, 111, 115, 116, 0, 0, 0, 102, 0, 0, 0, 0, 0, 104, 4, 106,
866                100, 0, 4, 110, 111, 110, 101, 100, 0, 4, 110, 111, 110, 101, 108, 0, 0, 0, 1, 104,
867                5, 100, 0, 6, 99, 108, 97, 117, 115, 101, 97, 3, 106, 106, 108, 0, 0, 0, 1, 104, 3,
868                100, 0, 4, 97, 116, 111, 109, 97, 0, 100, 0, 3, 110, 105, 108, 106, 106
869            ]
870        )
871    }
872
873    #[test]
874    #[cfg(feature = "zlib")]
875    fn gzip_bytes() {
876        use crate::to_gzip_bytes;
877        use flate2::Compression;
878
879        let list = RawTerm::List((0..100).into_iter().map(RawTerm::Int).collect());
880
881        // validated in elixir
882        // ```elixir
883        // expected |> :erlang.list_to_binary() |> :erlang.binary_to_term()
884        // ```
885
886        let expected = vec![
887            131, 80, 0, 0, 1, 250, 120, 156, 21, 196, 51, 150, 67, 1, 0, 0, 192, 191, 182, 109,
888            219, 182, 109, 198, 70, 149, 151, 251, 215, 201, 52, 83, 14, 130, 160, 152, 175, 18,
889            160, 6, 181, 168, 67, 61, 26, 208, 136, 38, 52, 163, 5, 173, 104, 67, 59, 58, 208, 137,
890            46, 116, 163, 7, 189, 232, 67, 63, 6, 48, 136, 33, 12, 99, 4, 163, 24, 195, 56, 38, 48,
891            137, 41, 76, 99, 6, 179, 152, 195, 60, 22, 176, 136, 37, 44, 99, 5, 171, 88, 195, 58,
892            54, 176, 137, 45, 108, 99, 7, 187, 216, 195, 62, 14, 112, 136, 35, 28, 227, 4, 167, 56,
893            195, 57, 46, 112, 137, 43, 92, 227, 6, 183, 184, 195, 61, 30, 240, 136, 39, 60, 227, 5,
894            175, 120, 195, 59, 62, 240, 137, 47, 124, 227, 7, 191, 248, 195, 63, 66, 8, 35, 130,
895            40, 98, 136, 35, 129, 36, 82, 72, 35, 131, 44, 114, 200, 163, 80, 170, 0, 4, 44, 58,
896            217,
897        ];
898
899        let output = to_gzip_bytes(list, Compression::new(6)).unwrap();
900
901        assert_eq!(expected, output);
902    }
903}