erlang_term/
raw_term.rs

1use crate::Term;
2use keylist::Keylist;
3use nom::error::Error;
4use nom::Err as NomErr;
5use num_bigint::BigInt;
6use ordered_float::OrderedFloat;
7use std::collections::HashMap;
8use strum::EnumDiscriminants;
9
10#[derive(Debug, Clone, Hash, PartialEq, EnumDiscriminants)]
11#[strum_discriminants(name(RawTermType))]
12#[cfg_attr(feature = "serde_impl", derive(Serialize, Deserialize))]
13/// Erlang Term Format types
14pub enum RawTerm {
15    // ATOM_CACHE_REF
16    SmallInt(u8),
17    Int(i32),
18    // OldFloat(String),
19    // NEW_PORT,
20    // NEW_PID,
21    SmallTuple(Vec<RawTerm>),
22    LargeTuple(Vec<RawTerm>),
23    Map(Vec<(RawTerm, RawTerm)>),
24    Nil,
25    String(Vec<u8>),
26    List(Vec<RawTerm>),
27    Improper(Box<RawTerm>),
28    Binary(Vec<u8>),
29    BitBinary {
30        binary: Vec<u8>,
31        bit: u8,
32        bits: u8,
33    },
34    SmallBigInt(BigInt),
35    LargeBigInt(BigInt),
36    Pid {
37        node: Box<RawTerm>,
38        id: u32,
39        serial: u32,
40        creation: u8,
41    },
42    NewPid {
43        node: Box<RawTerm>,
44        id: u32,
45        serial: u32,
46        creation: u32,
47    },
48    Port {
49        node: Box<RawTerm>,
50        id: u32,
51        creation: u8,
52    },
53    NewPort {
54        node: Box<RawTerm>,
55        id: u32,
56        creation: u32,
57    },
58    Ref {
59        node: Box<RawTerm>,
60        id: Vec<u32>,
61        creation: u8,
62    },
63    NewerRef {
64        node: Box<RawTerm>,
65        id: Vec<u32>,
66        creation: u32,
67    },
68    Function {
69        size: u32,
70        arity: u8,
71        uniq: [u8; 16],
72        index: u32,
73        module: Box<RawTerm>,
74        old_index: Box<RawTerm>,
75        old_uniq: Box<RawTerm>,
76        pid: Box<RawTerm>,
77        free_var: Vec<RawTerm>,
78    },
79    // NEWER_REFERENCE,
80    // FUN,
81    // EXPORT,
82    // BIT_BINARY,
83    Float(OrderedFloat<f64>),
84    Atom(String),
85    SmallAtom(String),
86    // REFERENCE_EXT_DEPRECATED,
87    AtomDeprecated(String),
88    SmallAtomDeprecated(String),
89}
90
91impl RawTerm {
92    pub fn from_bytes(input: &[u8]) -> Result<RawTerm, NomErr<Error<&[u8]>>> {
93        crate::from_bytes(input)
94    }
95
96    pub fn to_bytes(self) -> Vec<u8> {
97        crate::to_bytes(self)
98    }
99
100    #[cfg(feature = "zlib")]
101    pub fn to_gzip_bytes(self, level: flate2::Compression) -> std::io::Result<Vec<u8>> {
102        crate::to_gzip_bytes(self, level)
103    }
104
105    pub fn as_type(&self) -> RawTermType {
106        RawTermType::from(self)
107    }
108
109    pub fn as_general_type(&self) -> RawTermGeneralType {
110        RawTermGeneralType::from(self.as_type())
111    }
112
113    pub fn is_atom(&self) -> bool {
114        use RawTerm::*;
115        matches!(
116            self,
117            Atom(_) | AtomDeprecated(_) | SmallAtom(_) | SmallAtomDeprecated(_)
118        )
119    }
120
121    pub fn is_string(&self) -> bool {
122        use RawTerm::*;
123        matches!(self, Binary(_) | String(_))
124    }
125
126    /// if term is a string/binary or atom
127    pub fn is_string_like(&self) -> bool {
128        self.is_string() | self.is_atom()
129    }
130
131    pub fn is_integer(&self) -> bool {
132        use RawTerm::*;
133        matches!(self, SmallInt(_) | Int(_))
134    }
135
136    pub fn is_atom_pair(&self) -> bool {
137        use RawTerm::*;
138        match self {
139            SmallTuple(x) if x.len() == 2 => x[0].is_atom(),
140            _ => false,
141        }
142    }
143
144    pub fn is_string_map(&self) -> bool {
145        use RawTerm::*;
146        match self {
147            Map(x) => x.iter().all(|(a, _)| a.is_string_like()),
148            _ => false,
149        }
150    }
151
152    pub fn is_list(&self) -> bool {
153        use RawTerm::*;
154        matches!(self, List(_))
155    }
156
157    pub fn as_atom(self) -> Option<String> {
158        use RawTerm::*;
159        match self {
160            Atom(x) | AtomDeprecated(x) | SmallAtom(x) | SmallAtomDeprecated(x) => Some(x),
161            _ => None,
162        }
163    }
164
165    pub fn as_string(self) -> Option<String> {
166        match self {
167            RawTerm::Binary(x) | RawTerm::String(x) => {
168                Some(String::from_utf8(x).expect("binary not utf-8"))
169            }
170            _ => None,
171        }
172    }
173
174    pub fn as_string_like(self) -> Option<String> {
175        if self.is_string() {
176            self.as_string()
177        } else if self.is_atom() {
178            self.as_atom()
179        } else {
180            None
181        }
182    }
183
184    pub fn as_atom_pair(self) -> Option<(String, RawTerm)> {
185        use RawTerm::*;
186        match self {
187            SmallTuple(mut x) | LargeTuple(mut x) if x.len() == 2 => {
188                let b = x.pop().expect("length is two");
189                if let Some(a) = x.pop().expect("length is two").as_atom() {
190                    return Some((a, b));
191                }
192            }
193            _ => (),
194        }
195        None
196    }
197}
198
199impl From<Term> for RawTerm {
200    fn from(term: Term) -> RawTerm {
201        match term {
202            Term::Byte(x) => RawTerm::SmallInt(x),
203            Term::Int(x) => RawTerm::Int(x),
204            Term::Float(x) => RawTerm::Float(x),
205            Term::String(x) => string_to_raw_term(x),
206            Term::Atom(x) => atom_to_raw_term(x),
207            Term::Bytes(x) => RawTerm::Binary(x),
208            Term::Bool(x) => RawTerm::SmallAtom(x.to_string()),
209            Term::Nil => RawTerm::SmallAtom("nil".to_string()),
210            Term::BigInt(x) => big_int_to_raw_term(x),
211            Term::Charlist(x) => RawTerm::String(x),
212            Term::Keyword(x) => keyword_to_raw_term(x),
213            Term::List(x) => list_to_raw_term(x),
214            Term::Tuple(x) => tuple_to_raw_term(x),
215            Term::Map(x) => map_arbitrary_to_raw_term(x),
216            Term::Other(x) => x,
217        }
218    }
219}
220
221fn string_to_raw_term(string: String) -> RawTerm {
222    RawTerm::Binary(string.as_bytes().to_vec())
223}
224
225fn keyword_to_raw_term(keyword: Keylist<String, Term>) -> RawTerm {
226    let tmp: Vec<RawTerm> = keyword
227        .into_iter()
228        .map(|(a, b)| RawTerm::SmallTuple(vec![string_to_raw_term(a), RawTerm::from(b)]))
229        .collect();
230    RawTerm::List(tmp)
231}
232
233fn map_arbitrary_to_raw_term(map: HashMap<Term, Term>) -> RawTerm {
234    let tmp = map
235        .into_iter()
236        .map(|(k, v)| (RawTerm::from(k), RawTerm::from(v)))
237        .collect();
238    RawTerm::Map(tmp)
239}
240
241fn list_to_raw_term(list: Vec<Term>) -> RawTerm {
242    if list.is_empty() {
243        RawTerm::Nil
244    } else {
245        RawTerm::List(list.into_iter().map(RawTerm::from).collect())
246    }
247}
248
249fn tuple_to_raw_term(tuple: Vec<Term>) -> RawTerm {
250    let len = tuple.len();
251    let x = tuple.into_iter().map(RawTerm::from).collect();
252    if len < 16 {
253        RawTerm::SmallTuple(x)
254    } else {
255        RawTerm::LargeTuple(x)
256    }
257}
258
259fn big_int_to_raw_term(input: BigInt) -> RawTerm {
260    if input.bits() < (255 * 8) {
261        RawTerm::SmallBigInt(input)
262    } else {
263        RawTerm::LargeBigInt(input)
264    }
265}
266
267fn atom_to_raw_term(input: String) -> RawTerm {
268    if input.len() < 256 {
269        RawTerm::SmallAtom(input)
270    } else {
271        RawTerm::Atom(input)
272    }
273}
274
275#[derive(Debug, PartialEq, PartialOrd)]
276/// enum use for implement Ordering in the raw terms
277pub enum RawTermGeneralType {
278    // Improper should not be used for ordering.
279    Improper,
280    Number,
281    Atom,
282    Reference,
283    Fun,
284    Port,
285    Pid,
286    Tuple,
287    Map,
288    Nil,
289    List,
290    BitString,
291}
292
293impl From<RawTermType> for RawTermGeneralType {
294    fn from(item: RawTermType) -> RawTermGeneralType {
295        RawTermGeneralType::from(&item)
296    }
297}
298
299impl From<&RawTermType> for RawTermGeneralType {
300    fn from(item: &RawTermType) -> RawTermGeneralType {
301        use RawTermType::*;
302        match item {
303            SmallInt => RawTermGeneralType::Number,
304            Int => RawTermGeneralType::Number,
305            SmallTuple => RawTermGeneralType::Tuple,
306            LargeTuple => RawTermGeneralType::Tuple,
307            Map => RawTermGeneralType::Map,
308            Nil => RawTermGeneralType::Nil,
309            String => RawTermGeneralType::BitString,
310            List => RawTermGeneralType::List,
311            Improper => RawTermGeneralType::Improper,
312            Binary => RawTermGeneralType::BitString,
313            BitBinary => RawTermGeneralType::BitString,
314            SmallBigInt => RawTermGeneralType::Number,
315            LargeBigInt => RawTermGeneralType::Number,
316            Pid => RawTermGeneralType::Pid,
317            NewPid => RawTermGeneralType::Pid,
318            Port => RawTermGeneralType::Port,
319            NewPort => RawTermGeneralType::Port,
320            Ref => RawTermGeneralType::Reference,
321            NewerRef => RawTermGeneralType::Reference,
322            Function => RawTermGeneralType::Fun,
323            Float => RawTermGeneralType::Number,
324            Atom => RawTermGeneralType::Atom,
325            SmallAtom => RawTermGeneralType::Atom,
326            AtomDeprecated => RawTermGeneralType::Atom,
327            SmallAtomDeprecated => RawTermGeneralType::Atom,
328        }
329    }
330}
331
332#[cfg(test)]
333mod from_term_tests {
334    use crate::{from_bytes, read_binary, RawTerm};
335    use num_bigint::{BigInt, BigUint};
336
337    #[test]
338    fn small_int() {
339        let input = read_binary("bins/small_int.bin").unwrap();
340        let out = from_bytes(&input).unwrap();
341
342        assert_eq!(RawTerm::SmallInt(2), out);
343    }
344
345    #[test]
346    fn small_negative_int() {
347        let input = read_binary("bins/small_negative_int.bin").unwrap();
348        let out = from_bytes(&input).unwrap();
349
350        assert_eq!(RawTerm::Int(-2), out);
351    }
352
353    #[test]
354    fn int() {
355        let input = read_binary("bins/int.bin").unwrap();
356        let out = from_bytes(&input).unwrap();
357
358        assert_eq!(RawTerm::Int(1234578), out);
359    }
360
361    #[test]
362    fn negative_int() {
363        let input = read_binary("bins/negative_int.bin").unwrap();
364        let out = from_bytes(&input).unwrap();
365
366        assert_eq!(RawTerm::Int(-1234578), out);
367    }
368
369    #[test]
370    fn nil() {
371        let input = read_binary("bins/nil.bin").unwrap();
372        let out = from_bytes(&input).unwrap();
373
374        assert_eq!(RawTerm::AtomDeprecated("nil".to_string()), out);
375    }
376
377    #[test]
378    fn false_test() {
379        let input = read_binary("bins/false.bin").unwrap();
380        let out = from_bytes(&input).unwrap();
381
382        assert_eq!(RawTerm::AtomDeprecated("false".to_string()), out);
383    }
384
385    #[test]
386    fn true_test() {
387        let input = read_binary("bins/true.bin").unwrap();
388        let out = from_bytes(&input).unwrap();
389
390        assert_eq!(RawTerm::AtomDeprecated("true".to_string()), out);
391    }
392
393    #[test]
394    fn odd_atom() {
395        let input = read_binary("bins/odd_atom.bin").unwrap();
396        let out = from_bytes(&input).unwrap();
397
398        assert_eq!(RawTerm::SmallAtom("oddţ".to_string()), out);
399    }
400
401    #[test]
402    fn module_name() {
403        let input = read_binary("bins/module_name.bin").unwrap();
404        let out = from_bytes(&input).unwrap();
405
406        assert_eq!(
407            RawTerm::AtomDeprecated("Elixir.TermGenerator".to_string()),
408            out
409        );
410    }
411
412    #[test]
413    fn elixir_struct() {
414        let input = read_binary("bins/struct.bin").unwrap();
415        let out = from_bytes(&input).unwrap();
416
417        let expected = RawTerm::Map(
418            vec![
419                (
420                    RawTerm::AtomDeprecated("__struct__".to_string()),
421                    RawTerm::AtomDeprecated("Elixir.TestStruct".to_string()),
422                ),
423                (
424                    RawTerm::AtomDeprecated("a".to_string()),
425                    RawTerm::AtomDeprecated("nil".to_string()),
426                ),
427                (RawTerm::AtomDeprecated("b".to_string()), RawTerm::Int(1234)),
428            ]
429            .into_iter()
430            .collect(),
431        );
432
433        assert_eq!(expected, out);
434    }
435
436    #[test]
437    fn small_string() {
438        let input = read_binary("bins/small_string.bin").unwrap();
439        let out = from_bytes(&input).unwrap();
440
441        assert_eq!(RawTerm::Binary(b"just some text".to_vec()), out);
442    }
443
444    #[test]
445    fn binary() {
446        let input = read_binary("bins/binary.bin").unwrap();
447        let out = from_bytes(&input).unwrap();
448
449        assert_eq!(RawTerm::Binary(vec![1, 2, 3, 4]), out);
450    }
451
452    #[test]
453    fn bitbinary() {
454        let input = read_binary("bins/bitbinary.bin").unwrap();
455        let out = from_bytes(&input).unwrap();
456
457        assert_eq!(
458            RawTerm::BitBinary {
459                binary: vec![95],
460                bit: 23,
461                bits: 5
462            },
463            out
464        );
465    }
466
467    #[test]
468    fn large_string() {
469        let input = read_binary("bins/large_string.bin").unwrap();
470        let out = from_bytes(&input).unwrap();
471
472        if let RawTerm::Binary(x) = &out {
473            assert!(x.starts_with(b"Lorem ipsum dolor sit"))
474        } else {
475            assert!(false)
476        }
477    }
478
479    #[test]
480    fn float() {
481        let input = read_binary("bins/float.bin").unwrap();
482        let out = from_bytes(&input).unwrap();
483
484        assert_eq!(RawTerm::Float(12.515.into()), out);
485    }
486
487    #[test]
488    fn empty_list() {
489        let input = read_binary("bins/empty_list.bin").unwrap();
490        let out = from_bytes(&input).unwrap();
491
492        // assert_eq!(vec![RawTerm::List(vec![])], out);
493        assert_eq!(RawTerm::Nil, out);
494    }
495
496    #[test]
497    fn number_list() {
498        let input = read_binary("bins/number_list.bin").unwrap();
499        let out = from_bytes(&input).unwrap();
500
501        assert_eq!(RawTerm::String(vec![1, 2, 3, 4]), out);
502    }
503
504    #[test]
505    fn mixed_list() {
506        use crate::RawTerm::*;
507
508        let input = read_binary("bins/mixed_list.bin").unwrap();
509        let out = from_bytes(&input).unwrap();
510
511        assert_eq!(
512            List(vec![
513                SmallInt(1),
514                Binary(b"some".to_vec()),
515                SmallInt(2),
516                Binary(b"text".to_vec())
517            ]),
518            out
519        );
520    }
521
522    #[test]
523    fn improper_list() {
524        use crate::RawTerm::*;
525
526        let input = read_binary("bins/improper_list.bin").unwrap();
527        let out = from_bytes(&input).unwrap();
528
529        assert_eq!(
530            List(vec![
531                SmallInt(1),
532                SmallInt(6),
533                Improper(Box::new(SmallInt(2))),
534            ]),
535            out
536        );
537    }
538
539    #[test]
540    fn atom_map() {
541        let input = read_binary("bins/atom_map.bin").unwrap();
542        let out = from_bytes(&input).unwrap();
543
544        let mut map = Vec::new();
545
546        map.push((
547            RawTerm::AtomDeprecated("just".to_string()),
548            RawTerm::Binary(b"some key".to_vec()),
549        ));
550        map.push((
551            RawTerm::AtomDeprecated("other".to_string()),
552            RawTerm::Binary(b"value".to_vec()),
553        ));
554
555        assert_eq!(RawTerm::Map(map), out);
556    }
557
558    #[test]
559    fn map() {
560        use RawTerm::*;
561
562        let input = read_binary("bins/map.bin").unwrap();
563        if let Map(out) = from_bytes(&input).unwrap() {
564            let mut map = vec![
565                (Binary(b"float".to_vec()), Float(3.14.into())),
566                (
567                    List(vec![Binary(b"list as a key".to_vec())]),
568                    List(vec![
569                        Binary(b"another".to_vec()),
570                        Map(vec![(
571                            AtomDeprecated("test".to_string()),
572                            AtomDeprecated("false".to_string()),
573                        )]
574                        .into_iter()
575                        .collect()),
576                    ]),
577                ),
578                (SmallInt(1), Binary(b"one".to_vec())),
579                (
580                    AtomDeprecated("tuple".to_string()),
581                    SmallTuple(vec![SmallInt(1), AtomDeprecated("more".to_string())]),
582                ),
583                (
584                    Binary(b"large".to_vec()),
585                    SmallBigInt(BigInt::parse_bytes(b"123456789123456789", 10).unwrap()),
586                ),
587                (
588                    Binary(b"nested".to_vec()),
589                    Map(vec![(Binary(b"ok".to_vec()), Nil)].into_iter().collect()),
590                ),
591            ];
592
593            for item in out.iter() {
594                if let Some(index) =
595                    map.iter()
596                        .enumerate()
597                        .find_map(|(i, x)| if x == item { Some(i) } else { None })
598                {
599                    map.remove(index);
600                } else {
601                    panic!("input has more items then expected")
602                }
603            }
604
605            assert!(!out.is_empty());
606            assert!(map.is_empty());
607        } else {
608            assert!(false);
609        }
610    }
611
612    #[test]
613    fn keyword() {
614        let input = read_binary("bins/keyword.bin").unwrap();
615        let out = from_bytes(&input).unwrap();
616
617        let mut map = Vec::new();
618
619        map.push(RawTerm::SmallTuple(vec![
620            RawTerm::AtomDeprecated("just".to_string()),
621            RawTerm::Binary(b"some key".to_vec()),
622        ]));
623        map.push(RawTerm::SmallTuple(vec![
624            RawTerm::AtomDeprecated("other".to_string()),
625            RawTerm::Binary(b"value".to_vec()),
626        ]));
627        map.push(RawTerm::SmallTuple(vec![
628            RawTerm::AtomDeprecated("just".to_string()),
629            RawTerm::Int(1234),
630        ]));
631
632        assert_eq!(RawTerm::List(map), out);
633    }
634
635    #[test]
636    fn tuple() {
637        let input = read_binary("bins/tuple.bin").unwrap();
638        let out = from_bytes(&input).unwrap();
639        assert_eq!(
640            RawTerm::SmallTuple(vec![
641                RawTerm::Binary(b"test".to_vec()),
642                RawTerm::Binary(b"testing".to_vec())
643            ]),
644            out
645        );
646        let large_tuple = read_binary("bins/large_tuple.bin").unwrap();
647        let out = from_bytes(&large_tuple).unwrap();
648        let mut tuple = vec![];
649        for i in 1..401 {
650            if i < 256 {
651                tuple.push(RawTerm::SmallInt(i as u8));
652            } else {
653                tuple.push(RawTerm::Int(i));
654            }
655        }
656        let tuple = RawTerm::SmallTuple(vec![
657            RawTerm::AtomDeprecated("row_data".into()),
658            RawTerm::Binary(b"kkk".to_vec()),
659            RawTerm::LargeTuple(tuple),
660            RawTerm::SmallInt(10),
661        ]);
662        assert_eq!(tuple, out);
663        let bin = tuple.to_bytes();
664        assert_eq!(bin, large_tuple);
665    }
666
667    #[test]
668    fn small_big_int() {
669        let input = read_binary("bins/small_big_int.bin").unwrap();
670        let out = from_bytes(&input).unwrap();
671        assert_eq!(
672            RawTerm::SmallBigInt(BigInt::parse_bytes(b"123456789123456789123456789", 10).unwrap()),
673            out
674        );
675    }
676
677    #[test]
678    fn large_big_int() {
679        use num_traits::pow::Pow;
680
681        let input = read_binary("bins/large_big_int.bin").unwrap();
682        let out = from_bytes(&input).unwrap();
683        let nineninenine = BigUint::parse_bytes(b"999", 10).unwrap();
684
685        assert_eq!(
686            RawTerm::LargeBigInt(BigInt::from(nineninenine.clone().pow(&nineninenine))),
687            out
688        );
689    }
690
691    #[test]
692    fn pid() {
693        let input = read_binary("bins/pid.bin").unwrap();
694        let out = from_bytes(&input).unwrap();
695
696        assert_eq!(
697            RawTerm::Pid {
698                node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
699                id: 91,
700                serial: 0,
701                creation: 0
702            },
703            out
704        );
705    }
706    #[test]
707    fn new_pid() {
708        let input = read_binary("bins/new_pid.bin").unwrap();
709        let out = from_bytes(&input).unwrap();
710        let expect = RawTerm::NewPid {
711            node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
712            id: 79,
713            serial: 0,
714            creation: 0,
715        };
716        assert_eq!(expect, out);
717        assert_eq!(&input, &expect.to_bytes());
718    }
719    #[test]
720    fn function() {
721        let input = read_binary("bins/function.bin").unwrap();
722        let out = from_bytes(&input).unwrap();
723
724        assert_eq!(
725            RawTerm::Function {
726                size: 85,
727                arity: 2,
728                uniq: [149, 84, 239, 178, 136, 29, 208, 62, 138, 103, 212, 245, 20, 90, 180, 225],
729                index: 0,
730                module: Box::new(RawTerm::AtomDeprecated("Elixir.TermGenerator".to_string())),
731                old_index: Box::new(RawTerm::SmallInt(0)),
732                old_uniq: Box::new(RawTerm::Int(78292861)),
733                pid: Box::new(RawTerm::Pid {
734                    node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
735                    id: 0,
736                    serial: 0,
737                    creation: 0
738                }),
739                free_var: Vec::new()
740            },
741            out
742        );
743        // function included new_pid
744        // #Fun<big_data_redis_SUITE.0.96608257>
745        let input = &[
746            131, 112, 0, 0, 0, 88, 0, 184, 68, 0, 56, 201, 101, 109, 209, 140, 69, 18, 224, 71,
747            189, 151, 33, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 20, 98, 105, 103, 95, 100, 97, 116, 97,
748            95, 114, 101, 100, 105, 115, 95, 83, 85, 73, 84, 69, 97, 0, 98, 5, 194, 32, 1, 88, 100,
749            0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, 0, 3, 87, 0,
750            0, 0, 0, 0, 0, 0, 0,
751        ];
752        let expected = RawTerm::Function {
753            size: 88,
754            arity: 0,
755            uniq: [
756                184, 68, 0, 56, 201, 101, 109, 209, 140, 69, 18, 224, 71, 189, 151, 33,
757            ],
758            index: 0,
759            module: Box::new(RawTerm::AtomDeprecated("big_data_redis_SUITE".into())),
760            old_index: Box::new(RawTerm::SmallInt(0)),
761            old_uniq: Box::new(RawTerm::Int(96608257)),
762            pid: Box::new(RawTerm::NewPid {
763                node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".into())),
764                id: 855,
765                serial: 0,
766                creation: 0,
767            }),
768            free_var: Vec::new(),
769        };
770        let out = RawTerm::from_bytes(input).unwrap();
771        assert_eq!(expected, out);
772        assert_eq!(&expected.to_bytes(), input);
773    }
774
775    #[test]
776    fn port() {
777        let input = read_binary("bins/port.bin").unwrap();
778        let out = from_bytes(&input).unwrap();
779
780        assert_eq!(
781            RawTerm::Port {
782                node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
783                id: 3,
784                creation: 0
785            },
786            out
787        );
788    }
789
790    #[test]
791    fn reference() {
792        let input = read_binary("bins/ref.bin").unwrap();
793        let out = from_bytes(&input).unwrap();
794
795        assert_eq!(
796            RawTerm::Ref {
797                node: Box::new(RawTerm::AtomDeprecated("nonode@nohost".to_string())),
798                id: vec![158726, 438566918, 237133],
799                creation: 0
800            },
801            out
802        );
803    }
804
805    #[test]
806    #[cfg(feature = "zlib")]
807    fn gzip() {
808        let input = read_binary("bins/number_list_gzip.bin").unwrap();
809        let out = from_bytes(&input).unwrap();
810        assert!(out.is_list());
811    }
812}
813
814#[cfg(test)]
815mod as_type_tests {
816    use crate::raw_term::RawTermType;
817    use crate::RawTerm;
818
819    #[test]
820    fn as_type_binary() {
821        let term = RawTerm::Binary(vec![1, 2, 3, 4]);
822
823        assert_eq!(RawTermType::Binary, term.as_type())
824    }
825
826    #[test]
827    fn as_type_float() {
828        let term = RawTerm::Float(0.123.into());
829
830        assert_eq!(RawTermType::Float, term.as_type())
831    }
832
833    #[test]
834    fn as_type_nil() {
835        let term = RawTerm::Nil;
836
837        assert_eq!(RawTermType::Nil, term.as_type())
838    }
839
840    #[test]
841    fn as_type_map() {
842        let term = RawTerm::Map(
843            vec![(RawTerm::Atom(String::from("test")), RawTerm::Nil)]
844                .into_iter()
845                .collect(),
846        );
847
848        assert_eq!(RawTermType::Map, term.as_type())
849    }
850}
851
852#[test]
853fn raw_sub_type_ordering() {
854    use RawTermGeneralType::*;
855    // number < atom < reference < fun < port < pid < tuple < map < nil < list < bit string
856
857    // Improper should not be used for ordering.
858    assert!(Improper < Number);
859
860    assert!(Number < Atom);
861    assert!(Atom < Reference);
862    assert!(Reference < Fun);
863    assert!(Fun < Port);
864    assert!(Port < Pid);
865    assert!(Pid < Tuple);
866    assert!(Tuple < Map);
867    assert!(Map < Nil);
868    assert!(Nil < List);
869    assert!(List < BitString);
870
871    assert!(Number < BitString);
872    assert!(!(Number > BitString));
873}