1use crate::raw_term::{RawTermGeneralType, RawTermType};
2use crate::RawTerm;
3
4use keylist::Keylist;
5use nom::error::Error;
6use nom::Err as NomErr;
7use num_bigint::BigInt;
8use ordered_float::OrderedFloat;
9use std::collections::HashMap;
10use std::hash::{Hash, Hasher};
11use std::iter::FromIterator;
12
13mod improper_list;
14mod ord;
15
16pub use improper_list::ImproperList;
17
18#[derive(Debug, Clone, PartialEq)]
19#[cfg_attr(feature = "serde_impl", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde_impl", serde(untagged))]
21pub enum Term {
71 Byte(u8),
72 Int(i32),
73 Float(OrderedFloat<f64>),
74 String(String),
75 Atom(String),
76 Bytes(Vec<u8>),
77 Bool(bool),
78 Nil,
79 BigInt(BigInt),
80 Charlist(Vec<u8>),
81 Map(HashMap<Term, Term>),
82 Keyword(Keylist<String, Term>),
83 List(Vec<Term>),
84 Tuple(Vec<Term>),
85 Other(RawTerm),
86}
87
88impl From<RawTerm> for Term {
92 fn from(term: RawTerm) -> Self {
93 use RawTerm::*;
94 use Term::*;
95 match term {
96 SmallInt(x) => Byte(x),
97 RawTerm::Int(x) => Term::Int(x),
98 RawTerm::Float(x) => Term::Float(x),
99 Binary(x) if is_string_printable(&x) => match std::str::from_utf8(&x) {
100 Ok(s) => Term::String(s.to_string()),
101 Err(_) => Bytes(x),
102 },
103 Binary(x) => Bytes(x),
104 RawTerm::String(x) => Charlist(x),
105 SmallBigInt(x) => BigInt(x),
106 LargeBigInt(x) => BigInt(x),
107 RawTerm::List(x) => {
108 if x.iter().all(|x| x.is_atom_pair()) {
109 let map = Keylist::from_iter(
110 x.into_iter()
111 .map(|x| x.as_atom_pair().unwrap())
112 .map(|(a, b)| (a, Term::from(b))),
113 );
114 Term::Keyword(map)
115 } else {
116 Term::List(raw_term_list_to_term_list(x))
117 }
118 }
119 RawTerm::Nil => Term::List(Vec::new()),
120 SmallTuple(x) => Tuple(raw_term_list_to_term_list(x)),
121 LargeTuple(x) => Tuple(raw_term_list_to_term_list(x)),
122 AtomDeprecated(x) => atom_to_term(x),
123 SmallAtomDeprecated(x) => atom_to_term(x),
124 SmallAtom(x) => atom_to_term(x),
125 RawTerm::Atom(x) => atom_to_term(x),
126 RawTerm::Map(x) => Term::Map(
127 x.into_iter()
128 .map(|(a, b)| (Term::from(a), Term::from(b)))
129 .collect(),
130 ),
131 x => Other(x),
132 }
133 }
134}
135
136impl Hash for Term {
137 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
138 use Term::*;
139
140 match self {
141 Byte(x) => x.hash(state),
142 Int(x) => x.hash(state),
143 Float(x) => x.hash(state),
144 String(x) => x.hash(state),
145 Atom(x) => x.hash(state),
146 Bytes(x) => x.hash(state),
147 Bool(x) => x.hash(state),
148 Nil => "nil".hash(state),
149 BigInt(x) => x.hash(state),
150 Charlist(x) => x.hash(state),
151 Map(x) => {
152 state.write_u64(
154 x.iter()
155 .map(|kv| {
156 let mut h = std::collections::hash_map::DefaultHasher::new();
157 kv.hash(&mut h);
158 h.finish()
159 })
160 .fold(0, u64::wrapping_add),
161 )
162 }
163 Keyword(x) => x.hash(state),
164 List(x) => x.hash(state),
165 Tuple(x) => x.hash(state),
166 Other(x) => x.hash(state),
167 }
168 }
169}
170
171fn is_string_printable(binary: &[u8]) -> bool {
172 binary.iter().all(is_string_printable_byte)
173}
174
175fn is_string_printable_byte(byte: &u8) -> bool {
176 if byte >= &0xA0 {
179 return true;
180 }
181
182 if [10, 13, 9, 11, 8, 12, 27, 127, 7].contains(byte) {
184 return true;
185 }
186 if (0x20..=0x7E).contains(byte) {
188 return true;
189 }
190
191 false
192}
193
194fn raw_term_list_to_term_list(raw_list: Vec<RawTerm>) -> Vec<Term> {
195 raw_list.into_iter().map(Term::from).collect()
196}
197
198fn atom_to_term(atom: String) -> Term {
199 match atom.as_ref() {
200 "false" => Term::Bool(false),
201 "true" => Term::Bool(true),
202 "nil" => Term::Nil,
203 _ => Term::Atom(atom),
204 }
205}
206
207impl std::fmt::Display for Term {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 write!(f, "{}", print_elixir_term(self))
210 }
211}
212
213pub fn print_elixir_term(term: &Term) -> String {
214 use Term::*;
215
216 match term {
217 Bool(b) => b.to_string(),
218 Nil => "nil".to_string(),
219 String(s) => format!("{:?}", s),
220 Atom(a) => format_atom(a),
221 Byte(b) => b.to_string(),
222 Bytes(b) => {
223 let bytes: Vec<_> = b.iter().map(|x| x.to_string()).collect();
224 let mut inner = bytes.join(", ");
225 inner.insert_str(0, "<<");
226 inner.push_str(">>");
227 inner
228 }
229 Charlist(c) => {
230 format!("{:?}", c)
231 }
232 Int(i) => i.to_string(),
233 Float(f) => f.to_string(),
234 BigInt(b) => b.to_string(),
235 Keyword(k) => {
236 let list: Vec<_> = k
237 .iter()
238 .map(|(k, v)| {
239 let mut a = format_atom(k);
240 a = a.trim_start_matches(':').to_string();
241 format!("{}: {}", a, print_elixir_term(v))
242 })
243 .collect();
244 let mut inner = list.join(", ");
245 inner.insert(0, '[');
246 inner.push(']');
247 inner
248 }
249 List(l) => {
250 let list: Vec<_> = l.iter().map(print_elixir_term).collect();
251 let mut inner = list.join(", ");
252 inner.insert(0, '[');
253 inner.push(']');
254 inner
255 }
256 Tuple(t) => {
257 let list: Vec<_> = t.iter().map(print_elixir_term).collect();
258 let mut inner = list.join(", ");
259 inner.insert(0, '{');
260 inner.push('}');
261 inner
262 }
263 Map(m) => {
264 let list: Vec<_> = m
265 .iter()
266 .map(|(k, v)| format!("{} => {}", print_elixir_term(k), print_elixir_term(v)))
267 .collect();
268 let mut inner = list.join(", ");
269 inner.insert_str(0, "%{");
270 inner.push('}');
271 inner
272 }
273 other => format!("#{:?}", other),
274 }
275}
276
277fn format_atom(a: &str) -> String {
278 if a.is_empty() {
279 return String::from(r#":"""#);
280 }
281 if a.chars().all(|x| x.is_ascii_alphanumeric()) {
282 if a.chars().next().unwrap().is_ascii_uppercase() {
283 return a.to_string();
284 }
285 if !a.chars().next().unwrap().is_ascii_digit() {
286 return format!(":{}", a);
287 }
288 }
289 format!(r#":"{}""#, a)
290}
291
292impl Term {
293 pub fn from_bytes(input: &[u8]) -> Result<Term, NomErr<Error<&[u8]>>> {
294 Ok(Term::from(RawTerm::from_bytes(input)?))
295 }
296
297 pub fn to_bytes(self) -> Vec<u8> {
298 RawTerm::from(self).to_bytes()
299 }
300
301 #[cfg(feature = "zlib")]
302 pub fn to_gzip_bytes(self, level: flate2::Compression) -> std::io::Result<Vec<u8>> {
303 RawTerm::from(self).to_gzip_bytes(level)
304 }
305
306 pub fn as_type(&self) -> RawTermType {
307 match self {
308 Term::Byte(_) => RawTermType::SmallInt,
309 Term::Int(_) => RawTermType::Int,
310 Term::Float(_) => RawTermType::Float,
311 Term::String(_) => RawTermType::Binary,
312 Term::Atom(_) => RawTermType::Atom,
313 Term::Bytes(_) => RawTermType::Binary,
314 Term::Bool(_) => RawTermType::SmallAtom,
315 Term::Nil => RawTermType::SmallAtom,
316 Term::BigInt(_) => RawTermType::LargeBigInt,
317 Term::Charlist(_) => RawTermType::String,
318 Term::Map(_) => RawTermType::Map,
319 Term::Keyword(_) => RawTermType::List,
320 Term::List(_) => RawTermType::List,
321 Term::Tuple(_) => RawTermType::LargeTuple,
322 Term::Other(x) => x.as_type(),
323 }
324 }
325
326 pub fn as_general_type(&self) -> RawTermGeneralType {
327 RawTermGeneralType::from(self.as_type())
328 }
329
330 pub fn is_byte(&self) -> bool {
331 use Term::*;
332 matches!(self, Byte(_))
333 }
334
335 pub fn is_string(&self) -> bool {
336 use Term::*;
337 matches!(self, String(_))
338 }
339
340 pub fn is_atom(&self) -> bool {
341 use Term::*;
342 matches!(self, Atom(_))
343 }
344
345 pub fn is_tuple(&self) -> bool {
346 use Term::*;
347 matches!(self, Tuple(_))
348 }
349
350 pub fn is_pair_tuple(&self) -> bool {
359 use Term::*;
360 matches!(self, Tuple(x) if x.len() == 2)
361 }
362
363 pub fn is_list(&self) -> bool {
364 use Term::*;
365 matches!(self, List(_))
366 }
367
368 pub fn is_string_tuple_pair(&self) -> bool {
379 use Term::*;
380 matches!(self, Tuple(x) if (x.len() == 2) & x[0].is_string())
381 }
382
383 pub fn as_bool(self) -> Option<bool> {
384 use Term::*;
385 match self {
386 Bool(x) => Some(x),
387 _ => None,
388 }
389 }
390
391 pub fn as_nil(self) -> Option<()> {
392 use Term::*;
393 match self {
394 Nil => Some(()),
395 _ => None,
396 }
397 }
398
399 pub fn as_byte(self) -> Option<u8> {
400 use Term::*;
401 match self {
402 Byte(x) => Some(x),
403 _ => None,
404 }
405 }
406 pub fn as_int(self) -> Option<i32> {
407 use Term::*;
408 match self {
409 Int(x) => Some(x),
410 _ => None,
411 }
412 }
413 pub fn as_float(self) -> Option<f64> {
414 use Term::*;
415 match self {
416 Float(x) => Some(*x),
417 _ => None,
418 }
419 }
420 pub fn as_atom(self) -> Option<String> {
421 use Term::*;
422 match self {
423 Atom(x) => Some(x),
424 _ => None,
425 }
426 }
427 pub fn as_string(self) -> Option<String> {
428 use Term::*;
429 match self {
430 String(x) => Some(x),
431 _ => None,
432 }
433 }
434 pub fn as_bytes(self) -> Option<Vec<u8>> {
435 use Term::*;
436 match self {
437 Bytes(x) => Some(x),
438 _ => None,
439 }
440 }
441
442 pub fn as_charlist(self) -> Option<Vec<u8>> {
443 use Term::*;
444 match self {
445 Charlist(x) => Some(x),
446 _ => None,
447 }
448 }
449
450 pub fn as_big_int(self) -> Option<BigInt> {
451 use Term::*;
452 match self {
453 BigInt(x) => Some(x),
454 _ => None,
455 }
456 }
457
458 pub fn as_keyword(self) -> Option<Keylist<String, Term>> {
459 use Term::*;
460 match self {
461 Keyword(x) => Some(x),
462 _ => None,
463 }
464 }
465
466 pub fn as_list(self) -> Option<Vec<Term>> {
467 use Term::*;
468 match self {
469 List(x) => Some(x),
470 _ => None,
471 }
472 }
473
474 pub fn as_tuple(self) -> Option<Vec<Term>> {
475 use Term::*;
476 match self {
477 Tuple(x) => Some(x),
478 _ => None,
479 }
480 }
481
482 pub fn as_map(self) -> Option<HashMap<Term, Term>> {
483 use Term::*;
484 match self {
485 Map(x) => Some(x),
486 _ => None,
487 }
488 }
489
490 pub fn as_string_map(self) -> Option<HashMap<String, Term>> {
495 use Term::*;
496 match self {
497 Map(x) if x.keys().all(|y| y.is_string()) => {
498 let new_map = HashMap::from_iter(
499 x.into_iter()
500 .map(|(k, v)| (k.as_string().expect("checked this in the match"), v)),
501 );
502 Some(new_map)
503 }
504 _ => None,
505 }
506 }
507
508 pub fn as_atom_map(self) -> Option<HashMap<String, Term>> {
513 use Term::*;
514 match self {
515 Map(x) if x.keys().all(|y| y.is_atom()) => {
516 let new_map = HashMap::from_iter(
517 x.into_iter()
518 .map(|(k, v)| (k.as_atom().expect("checked this in the match"), v)),
519 );
520 Some(new_map)
521 }
522 _ => None,
523 }
524 }
525}
526
527macro_rules! impl_from_float {
528 ($type: ty) => {
529 impl From<$type> for Term {
530 fn from(input: $type) -> Term {
531 Term::Float((input as f64).into())
532 }
533 }
534 };
535}
536
537macro_rules! impl_from_integer {
538 ($type: ty) => {
539 impl From<$type> for Term {
540 fn from(input: $type) -> Term {
541 Term::Int(input as i32)
542 }
543 }
544 };
545}
546
547macro_rules! impl_from_big_integer {
548 ($type: ty) => {
549 impl From<$type> for Term {
550 fn from(input: $type) -> Term {
551 Term::BigInt(BigInt::from(input))
552 }
553 }
554 };
555}
556
557impl From<bool> for Term {
558 fn from(input: bool) -> Term {
559 Term::Bool(input)
560 }
561}
562
563impl From<u8> for Term {
564 fn from(input: u8) -> Term {
565 Term::Byte(input)
566 }
567}
568
569impl From<()> for Term {
570 fn from(_input: ()) -> Term {
571 Term::Nil
572 }
573}
574
575impl From<String> for Term {
576 fn from(input: String) -> Term {
577 Term::String(input)
578 }
579}
580
581impl From<&str> for Term {
582 fn from(input: &str) -> Term {
583 Term::String(String::from(input))
584 }
585}
586
587macro_rules! impl_tuple {
588 ($($idx:tt $t:tt),+) => {
589 impl<$($t,)+> From<($($t,)+)> for Term
590 where
591 $($t: Into<Term>,)+
592 {
593 fn from(input: ($($t,)+)) -> Self {
594 Term::Tuple(vec!($(
595 input.$idx.into(),
596 )+))
597 }
598 }
599 };
600}
601
602impl_tuple!(0 A);
603impl_tuple!(0 A, 1 B);
604impl_tuple!(0 A, 1 B, 2 C);
605impl_tuple!(0 A, 1 B, 2 C, 3 D);
606impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E);
607impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F);
608impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G);
609impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H);
610impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I);
611impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J);
612impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K);
613impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L);
614impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M);
615impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N);
616impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O);
617impl_tuple!(0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G, 7 H, 8 I, 9 J, 10 K, 11 L, 12 M, 13 N, 14 O, 15 P);
618
619impl<T: Into<Term>> From<Vec<T>> for Term {
620 fn from(input: Vec<T>) -> Term {
621 let data: Vec<Term> = input.into_iter().map(|x| x.into()).collect();
622 if data.iter().all(|x| x.is_byte()) {
623 Term::Bytes(data.into_iter().map(|x| x.as_byte().unwrap()).collect())
624 } else if data.iter().all(|x| x.is_string_tuple_pair()) {
625 Term::Keyword(Keylist::from_iter(
626 data.into_iter()
627 .map(|x| x.as_tuple().unwrap())
628 .map(|mut x| {
629 let second = x.pop().unwrap();
630 let first = x.pop().unwrap();
631 (first, second)
632 })
633 .map(|(a, b)| (a.as_string().unwrap(), b)),
634 ))
635 } else if data.iter().all(|x| x.is_pair_tuple()) {
636 Term::Map(HashMap::from_iter(
637 data.into_iter()
638 .map(|x| x.as_tuple().unwrap())
639 .map(|mut x| {
640 let second = x.pop().unwrap();
641 let first = x.pop().unwrap();
642 (first, second)
643 }),
644 ))
645 } else {
646 Term::List(data)
647 }
648 }
649}
650
651impl<K: Into<Term>, V: Into<Term>> From<HashMap<K, V>> for Term {
652 fn from(input: HashMap<K, V>) -> Term {
653 Term::Map(HashMap::from_iter(
654 input.into_iter().map(|(k, v)| (k.into(), v.into())),
655 ))
656 }
657}
658
659impl_from_float!(f32);
660impl_from_float!(f64);
661impl_from_integer!(i8);
662impl_from_integer!(i16);
663impl_from_integer!(u16);
664impl_from_integer!(i32);
665impl_from_big_integer!(usize);
666impl_from_big_integer!(u32);
667impl_from_big_integer!(i64);
668impl_from_big_integer!(u64);
669impl_from_big_integer!(i128);
670impl_from_big_integer!(u128);
671
672#[test]
673fn is_string_printable_test() {
674 let data = &[7, 33, 125];
675 assert!(is_string_printable(data));
676 assert!(std::str::from_utf8(data).is_ok());
677
678 let data = &[194, 160];
679 assert!(is_string_printable(data));
680 assert!(std::str::from_utf8(data).is_ok());
681
682 let data = &[1, 2, 3, 4];
684 assert!(!is_string_printable(data));
685 assert!(std::str::from_utf8(data).is_ok());
686
687 let data = &[202, 218, 82, 75, 227, 11, 203, 41, 103, 208, 244, 215];
689 assert!(is_string_printable(data));
690 assert!(std::str::from_utf8(data).is_err())
691}
692
693#[cfg(test)]
694mod convert_tests {
695 use crate::{from_bytes, read_binary, RawTerm, Term};
696 use keylist::Keylist;
697 use num_bigint::BigInt;
698 use std::collections::HashMap;
699
700 #[test]
701 fn mixed_list() {
702 use crate::Term::*;
703
704 let input = read_binary("bins/mixed_list.bin").unwrap();
705 let out = from_bytes(&input).unwrap();
706
707 assert_eq!(
708 List(vec![
709 Byte(1),
710 String("some".to_string()),
711 Byte(2),
712 String("text".to_string())
713 ]),
714 Term::from(out)
715 );
716 }
717
718 #[test]
719 fn number_list() {
720 use crate::Term::*;
721
722 let input = read_binary("bins/number_list.bin").unwrap();
723 let out = from_bytes(&input).unwrap();
724
725 assert_eq!(Charlist(vec![1, 2, 3, 4]), Term::from(out));
726 }
727
728 #[test]
729 fn binary() {
730 use crate::Term::*;
731
732 let input = read_binary("bins/binary.bin").unwrap();
733 let out = from_bytes(&input).unwrap();
734
735 assert_eq!(Bytes(vec![1, 2, 3, 4]), Term::from(out));
736 }
737
738 #[test]
739 fn binary_non_utf8() {
740 use crate::Term::*;
741
742 let input = read_binary("bins/non_utf8_string.bin").unwrap();
743 let out = from_bytes(&input).unwrap();
744
745 assert_eq!(
746 Bytes(vec![
747 143, 45, 211, 57, 243, 220, 73, 235, 239, 201, 232, 189, 101
748 ]),
749 Term::from(out)
750 );
751 }
752
753 #[test]
754 fn binary_utf8() {
755 use crate::Term::*;
756
757 let input = read_binary("bins/small_string.bin").unwrap();
758 let out = from_bytes(&input).unwrap();
759
760 assert_eq!(
761 String(std::string::String::from("just some text")),
762 Term::from(out)
763 );
764 }
765
766 #[test]
767 fn keyword() {
768 let input = read_binary("bins/keyword.bin").unwrap();
769 let out = from_bytes(&input).unwrap();
770
771 let mut expected = Keylist::new();
772 expected.push("just".to_string(), Term::String("some key".to_string()));
773 expected.push("other".to_string(), Term::String("value".to_string()));
774 expected.push("just".to_string(), Term::Int(1234));
775
776 assert_eq!(Term::Keyword(expected), Term::from(out));
777 }
778
779 #[test]
780 fn atom_map() {
781 let input = read_binary("bins/atom_map.bin").unwrap();
782 let out = from_bytes(&input).unwrap();
783
784 let mut expected = HashMap::new();
785 expected.insert(
786 Term::Atom("just".to_string()),
787 Term::String("some key".to_string()),
788 );
789 expected.insert(
790 Term::Atom("other".to_string()),
791 Term::String("value".to_string()),
792 );
793
794 assert_eq!(Term::Map(expected), Term::from(out));
795 }
796
797 #[test]
798 fn map() {
799 use std::iter::FromIterator;
800
801 let input = read_binary("bins/map.bin").unwrap();
802 let out = from_bytes(&input).unwrap();
803
804 let mut sub = HashMap::new();
805 sub.insert(Term::Atom("test".to_string()), Term::Bool(false));
806 let mut nested = HashMap::new();
807 nested.insert(Term::String("ok".to_string()), Term::List(Vec::new()));
808
809 let expected = HashMap::from_iter(vec![
810 (Term::Byte(1), Term::String("one".to_string())),
811 (
812 Term::Atom("tuple".to_string()),
813 Term::Tuple(vec![Term::Byte(1), Term::Atom("more".to_string())]),
814 ),
815 (
816 Term::List(vec![Term::String("list as a key".to_string())]),
817 Term::List(vec![Term::String("another".to_string()), Term::Map(sub)]),
818 ),
819 (Term::String("float".to_string()), Term::Float(3.14.into())),
820 (
821 Term::String("large".to_string()),
822 Term::BigInt(BigInt::parse_bytes(b"123456789123456789", 10).unwrap()),
823 ),
824 (Term::String("nested".to_string()), Term::Map(nested)),
825 ]);
826
827 assert_eq!(Term::Map(expected), Term::from(out));
828 }
829
830 #[test]
831 fn nil() {
832 let out = RawTerm::Atom("nil".to_string());
833 assert_eq!(Term::Nil, Term::from(out));
834 }
835
836 #[test]
837 fn false_test() {
838 let out = RawTerm::Atom("false".to_string());
839 assert_eq!(Term::Bool(false), Term::from(out));
840 }
841
842 #[test]
843 fn true_test() {
844 let out = RawTerm::Atom("true".to_string());
845 assert_eq!(Term::Bool(true), Term::from(out));
846 }
847}
848
849#[cfg(test)]
850mod from_tests {
851 use crate::Term;
852 use keylist::Keylist;
853 use num_bigint::BigInt;
854 use std::collections::HashMap;
855 use std::iter::FromIterator;
856
857 #[test]
858 fn from_i32() {
859 assert_eq!(Term::Int(12345), 12345i32.into())
860 }
861
862 #[test]
863 fn from_u8() {
864 assert_eq!(Term::Byte(3), 3u8.into())
865 }
866
867 #[test]
868 fn from_u32() {
869 assert_eq!(Term::BigInt(BigInt::from(12345)), 12345u32.into())
870 }
871
872 #[test]
873 fn from_i128() {
874 assert_eq!(
875 Term::BigInt(BigInt::from(1111111111112345i128)),
876 1111111111112345i128.into()
877 )
878 }
879
880 #[test]
881 fn from_str() {
882 assert_eq!(Term::String(String::from("test")), "test".into())
883 }
884
885 #[test]
886 fn from_string() {
887 assert_eq!(
888 Term::String(String::from("test")),
889 String::from("test").into()
890 )
891 }
892
893 #[test]
894 fn from_list_to_keyword() {
895 let input = vec![("test", 12), ("testing", 129)];
896 let expected = Term::Keyword(Keylist::from(vec![
897 ("test".to_string(), 12.into()),
898 ("testing".to_string(), 129.into()),
899 ]));
900 assert_eq!(expected, input.into())
901 }
902
903 #[test]
904 fn from_list_keyword_to_map() {
905 use Term::*;
906 let input = vec![(vec!["test"], 12), (vec!["testing"], 129)];
907 let expected = Term::Map(HashMap::from_iter(vec![
908 (List(vec!["test".into()]), 12.into()),
909 (List(vec!["testing".into()]), 129.into()),
910 ]));
911 assert_eq!(expected, input.into())
912 }
913
914 #[test]
915 fn from_list_nested() {
916 use Term::*;
917 let input = vec![vec![12], vec![1234]];
918 let expected = Term::List(vec![List(vec![12.into()]), List(vec![1234.into()])]);
919 assert_eq!(expected, input.into())
920 }
921
922 #[test]
923 fn from_list() {
924 let input = vec!["test", "testing", "more", "another"];
925 let expected = Term::List(vec![
926 "test".into(),
927 "testing".into(),
928 "more".into(),
929 "another".into(),
930 ]);
931 assert_eq!(expected, input.into())
932 }
933
934 #[test]
935 fn from_map() {
936 use std::collections::HashMap;
937 use std::iter::FromIterator;
938
939 let map = HashMap::from_iter(vec![(1u8, "test"), (5u8, "testing")]);
940
941 assert_eq!(
942 Term::Map(HashMap::from_iter(vec![
943 (1u8.into(), "test".into()),
944 (5u8.into(), "testing".into())
945 ])),
946 map.into()
947 );
948 }
949
950 #[test]
951 fn from_tuple_1() {
952 let expected = Term::Tuple(vec![0.into()]);
953
954 assert_eq!(expected, (0,).into())
955 }
956
957 #[test]
958 fn from_tuple_2() {
959 let expected = Term::Tuple(vec![0.into(), 1.into()]);
960
961 assert_eq!(expected, (0, 1).into())
962 }
963
964 #[test]
965 fn from_tuple_16() {
966 let expected = Term::Tuple((0..16).map(Term::from).collect());
967
968 assert_eq!(
969 expected,
970 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15).into()
971 )
972 }
973}
974
975#[cfg(test)]
976mod print {
977 use super::print_elixir_term;
978 use crate::{RawTerm, Term};
979 use keylist::Keylist;
980 use num_bigint::BigInt;
981 use std::collections::HashMap;
982 use std::iter::FromIterator;
983
984 #[test]
985 fn display() {
986 let keylist: Keylist<String, Term> = Keylist::from_iter(vec![
987 ("test".into(), 1.into()),
988 ("Test".into(), 2.into()),
989 ("1234Test".into(), 3.into()),
990 ]);
991 assert_eq!(
992 r#"[test: 1, Test: 2, "1234Test": 3]"#,
993 Term::Keyword(keylist).to_string()
994 );
995 }
996
997 #[test]
998 fn elixir_term() {
999 assert_eq!(
1000 "\"testing\"",
1001 print_elixir_term(&Term::String(String::from("testing")))
1002 );
1003 assert_eq!("123", print_elixir_term(&Term::Byte(123)));
1004 assert_eq!("nil", print_elixir_term(&Term::Nil));
1005 assert_eq!(
1006 ":testing",
1007 print_elixir_term(&Term::Atom(String::from("testing")))
1008 );
1009 assert_eq!(
1010 "NiceModule",
1011 print_elixir_term(&Term::Atom(String::from("NiceModule")))
1012 );
1013 assert_eq!(
1014 ":\":D:D\"",
1015 print_elixir_term(&Term::Atom(String::from(":D:D")))
1016 );
1017 assert_eq!(
1018 ":\"1234testing\"",
1019 print_elixir_term(&Term::Atom(String::from("1234testing")))
1020 );
1021 assert_eq!(
1022 "<<1, 2, 3, 4, 5, 6, 7>>",
1023 print_elixir_term(&Term::Bytes(vec![1, 2, 3, 4, 5, 6, 7]))
1024 );
1025 assert_eq!(
1026 "[1, 2, 3, 4, 5, 6, 7]",
1027 print_elixir_term(&Term::Charlist(vec![1, 2, 3, 4, 5, 6, 7]))
1028 );
1029 assert_eq!(
1030 "3.123124123123123",
1031 print_elixir_term(&Term::Float(3.123_124_123_123_123.into()))
1032 );
1033 assert_eq!("123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789", print_elixir_term(&Term::BigInt(BigInt::parse_bytes(b"123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789", 10).unwrap())));
1034 let keylist: Keylist<String, Term> = Keylist::from_iter(vec![
1035 ("test".into(), 1.into()),
1036 ("Test".into(), 2.into()),
1037 ("1234Test".into(), 3.into()),
1038 ]);
1039 assert_eq!(
1040 r#"[test: 1, Test: 2, "1234Test": 3]"#,
1041 print_elixir_term(&Term::Keyword(keylist))
1042 );
1043 let list = vec![
1044 "hallo".into(),
1045 Term::Byte(123),
1046 Term::Nil,
1047 Term::Bytes(vec![1, 2, 3, 4, 5, 6, 7]),
1048 ];
1049 assert_eq!(
1050 r#"["hallo", 123, nil, <<1, 2, 3, 4, 5, 6, 7>>]"#,
1051 print_elixir_term(&Term::List(list))
1052 );
1053 let list = vec![
1054 "hallo".into(),
1055 Term::Byte(123),
1056 Term::Nil,
1057 Term::Bytes(vec![1, 2, 3, 4, 5, 6, 7]),
1058 ];
1059 assert_eq!(
1060 r#"{"hallo", 123, nil, <<1, 2, 3, 4, 5, 6, 7>>}"#,
1061 print_elixir_term(&Term::Tuple(list))
1062 );
1063 let map: HashMap<Term, Term> = HashMap::from_iter(vec![
1064 ("test".into(), 1.into()),
1065 ("Test".into(), 2.into()),
1066 ("1234Test".into(), 3.into()),
1067 ("testing testing".into(), 4.into()),
1068 ]);
1069 let map_text = print_elixir_term(&Term::Map(map));
1070 assert!(map_text.contains("Test"));
1071 assert!(map_text.contains("%{"));
1072 assert!(map_text.contains(r#""1234Test" => 3"#));
1073
1074 let map = HashMap::from_iter(vec![
1075 (Term::List(vec!["test".into()]), 12.into()),
1076 (Term::List(vec!["testing".into()]), 129.into()),
1077 ]);
1078
1079 let map_text = print_elixir_term(&Term::Map(map));
1080 assert!(map_text.contains(r#"["test"] => 12"#));
1081 assert!(map_text.contains(r#"["testing"] => 129"#));
1082 assert!(map_text.contains("%{"));
1083
1084 assert_eq!(
1085 "#Other(Int(-123))",
1086 print_elixir_term(&Term::Other(RawTerm::Int(-123)))
1087 );
1088 }
1089}
1090
1091#[cfg(all(test, feature = "serde_impl"))]
1092mod serde_tests {
1093 use crate::{RawTerm, Term};
1094 #[test]
1095 fn json_round_trip() {
1096 let input = r#"
1097 {
1098 "number": 1,
1099 "float": 3.14,
1100 "list": [1,2,3,4, {"nested": "true"}],
1101 "map": {
1102 "test": 123456
1103 },
1104 "string": "testing",
1105 "boolean": true,
1106 "none": null
1107 }
1108 "#;
1109 let value: serde_json::Value = serde_json::from_str(input).unwrap();
1110 let term: Term = serde_json::from_value(value.clone()).unwrap();
1111 let raw_term = RawTerm::from(term);
1112 let bytes = raw_term.to_bytes();
1113 let new_raw_term = RawTerm::from_bytes(&bytes).unwrap();
1114 let new_term = Term::from(new_raw_term);
1115 let json = serde_json::to_value(&new_term).unwrap();
1116
1117 assert_eq!(value, json);
1118 }
1119
1120 #[test]
1121 fn elixir_round_trip() {
1122 let input = vec![
1137 131, 108, 0, 0, 0, 7, 104, 2, 100, 0, 6, 110, 117, 109, 98, 101, 114, 97, 1, 104, 2,
1138 100, 0, 5, 102, 108, 111, 97, 116, 70, 64, 9, 30, 184, 81, 235, 133, 31, 104, 2, 100,
1139 0, 4, 108, 105, 115, 116, 108, 0, 0, 0, 5, 97, 1, 97, 2, 97, 3, 97, 4, 116, 0, 0, 0, 1,
1140 109, 0, 0, 0, 6, 110, 101, 115, 116, 101, 100, 109, 0, 0, 0, 4, 116, 114, 117, 101,
1141 106, 104, 2, 100, 0, 3, 109, 97, 112, 116, 0, 0, 0, 1, 109, 0, 0, 0, 4, 116, 101, 115,
1142 116, 98, 0, 1, 226, 64, 104, 2, 100, 0, 6, 115, 116, 114, 105, 110, 103, 109, 0, 0, 0,
1143 7, 116, 101, 115, 116, 105, 110, 103, 104, 2, 100, 0, 7, 98, 111, 111, 108, 101, 97,
1144 110, 100, 0, 4, 116, 114, 117, 101, 104, 2, 100, 0, 4, 110, 111, 110, 101, 100, 0, 3,
1145 110, 105, 108, 106,
1146 ];
1147
1148 let adjusted_input = vec![
1162 131, 108, 0, 0, 0, 7, 104, 2, 109, 0, 0, 0, 6, 110, 117, 109, 98, 101, 114, 97, 1, 104,
1163 2, 109, 0, 0, 0, 5, 102, 108, 111, 97, 116, 70, 64, 9, 30, 184, 81, 235, 133, 31, 104,
1164 2, 109, 0, 0, 0, 4, 108, 105, 115, 116, 108, 0, 0, 0, 5, 97, 1, 97, 2, 97, 3, 97, 4,
1165 116, 0, 0, 0, 1, 109, 0, 0, 0, 6, 110, 101, 115, 116, 101, 100, 109, 0, 0, 0, 4, 116,
1166 114, 117, 101, 106, 104, 2, 109, 0, 0, 0, 3, 109, 97, 112, 116, 0, 0, 0, 1, 109, 0, 0,
1167 0, 4, 116, 101, 115, 116, 98, 0, 1, 226, 64, 104, 2, 109, 0, 0, 0, 6, 115, 116, 114,
1168 105, 110, 103, 109, 0, 0, 0, 7, 116, 101, 115, 116, 105, 110, 103, 104, 2, 109, 0, 0,
1169 0, 7, 98, 111, 111, 108, 101, 97, 110, 119, 4, 116, 114, 117, 101, 104, 2, 109, 0, 0,
1170 0, 4, 110, 111, 110, 101, 119, 3, 110, 105, 108, 106,
1171 ];
1172
1173 let term = Term::from_bytes(&adjusted_input).unwrap();
1174 let json = serde_json::to_value(&term).unwrap();
1175 let new_term: Term = serde_json::from_value(json).unwrap();
1176 let output = new_term.to_bytes();
1177
1178 assert_eq!(adjusted_input, output);
1179
1180 let term = Term::from_bytes(&input).unwrap();
1182 let json = serde_json::to_value(&term).unwrap();
1183 let new_term: Term = serde_json::from_value(json).unwrap();
1184 let output = new_term.to_bytes();
1185
1186 assert_eq!(adjusted_input, output);
1187 }
1188}