1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Library to convert Erlang External Term Format to Rust objects, without using erlang NIFs.
//!
//!
//! ```sh
//! elixir -e ":erlang.term_to_binary([1,2,3,4]) |> IO.inspect()" | sed -e 's/<</[/g' | sed -e 's/>>/]/g'
//! ```
//!
//! Copy that over to rust
//!
//! ```
//! use erlang_term::Term;
//!
//! let input = &[131, 107, 0, 4, 1, 2, 3, 4];
//! let term = Term::from_bytes(input);
//! assert_eq!(Ok(Term::Charlist([1, 2, 3, 4].to_vec())), term);
//! ```
//!
//! Or if you want more controle over the external term format:
//! ```
//! use erlang_term::RawTerm;
//!
//! let input = &[131, 107, 0, 4, 1, 2, 3, 4];
//!
//! let term = RawTerm::from_bytes(input);
//! assert_eq!(Ok(RawTerm::String([1, 2, 3, 4].to_vec())), term);
//! ```
//!
//! The `Term` enum is more what you will find in elixir.
//! The `RawTerm` enum takes the naming from the external term format spec.
//!
//! This is already apparent in the above example. In Erlang a string is just a list of characters and in Elixir this is called a Charlist.
//!
//! In this library I tried to split logic and convertion, so in the `RawTerm` there is only conversion between binary and rust enum and in the `Term` there is logic to convert that to a usable interface.
//! Therefore `RawTerm` to binary is one-to-one and onto. But `Term` to `RawTerm` there will be information thrown away.
//!
//! There is an optional `serde` feature.
//!
//! More examples:
//!
//! ```
//! use erlang_term::RawTerm;
//! use std::iter::FromIterator;
//!
//! let map = RawTerm::Map(vec![
//!     (RawTerm::SmallAtom(String::from("test")), RawTerm::SmallTuple(vec![RawTerm::SmallAtom(String::from("ok")), RawTerm::SmallInt(15)])),    
//!     (RawTerm::SmallAtom(String::from("another_key")), RawTerm::Binary(b"this is a string".to_vec())),
//!     (RawTerm::SmallAtom(String::from("number")), RawTerm::Float(3.1415)),
//! ]);
//!
//! let binary = vec![
//!     131, 116, 0, 0, 0, 3, 119, 4, 116, 101, 115, 116, 104, 2, 119, 2, 111, 107, 97, 15, 119, 11, 97, 110, 111, 116, 104, 101, 114, 95, 107, 101, 121, 109, 0, 0, 0, 16, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 116, 114, 105, 110, 103, 119, 6, 110, 117, 109, 98, 101, 114, 70, 64, 9, 33, 202, 192, 131, 18, 111
//! ];
//!
//! assert_eq!(map.to_bytes(), binary);
//! ```
//!

// http://erlang.org/doc/apps/erts/erl_ext_dist.html#distribution-header
// https://godoc.org/github.com/goerlang/etf#Term

extern crate nom;
extern crate num_bigint;
extern crate num_traits;
#[cfg(feature = "serde_impl")]
#[macro_use]
extern crate serde_derive;

use std::fs::File;
use std::io::{Read, Result as IoResult};

pub mod consts;
pub mod dump;
pub mod parse;
pub mod raw_term;
pub mod term;

pub use dump::to_bytes;
pub use parse::from_bytes;
pub use raw_term::RawTerm;
pub use term::Term;

pub fn read_binary(input: &str) -> IoResult<Vec<u8>> {
    let mut file = File::open(input)?;
    let mut buffer = Vec::new();

    file.read_to_end(&mut buffer)?;
    Ok(buffer)
}