erlang_term/lib.rs
1//! Library to convert Erlang External Term Format to Rust objects, without using erlang NIFs.
2//!
3//! # Installation
4//!
5//! ```toml
6//! [dependencies]
7//! erlang-term = "1.1.0"
8//! ```
9//!
10//! # Usage
11//!
12//! ```sh
13//! elixir -e ":erlang.term_to_binary([1,2,3,4]) |> IO.inspect()" | sed -e 's/<</[/g' | sed -e 's/>>/]/g'
14//! ```
15//!
16//! Copy that over to rust
17//!
18//! ```
19//! use erlang_term::Term;
20//!
21//! let input = &[131, 107, 0, 4, 1, 2, 3, 4];
22//! let term = Term::from_bytes(input);
23//! assert_eq!(Ok(Term::Charlist([1, 2, 3, 4].to_vec())), term);
24//! ```
25//!
26//! Or if you want more controle over the external term format:
27//!
28//! ```
29//! use erlang_term::RawTerm;
30//!
31//! let input = &[131, 107, 0, 4, 1, 2, 3, 4];
32//!
33//! let term = RawTerm::from_bytes(input);
34//! assert_eq!(Ok(RawTerm::String([1, 2, 3, 4].to_vec())), term);
35//! ```
36//!
37//! The `Term` enum is more what you will find in elixir.
38//! The `RawTerm` enum takes the naming from the external term format spec.
39//!
40//! 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.
41//!
42//! 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.
43//! Therefore `RawTerm` to binary is one-to-one and onto. But `Term` to `RawTerm` there will be information thrown away.
44//!
45//! # Features
46//!
47//! There is an optional `serde` feature.
48//!
49//! ```toml
50//! erlang-term = {version = "1.1.0", features = ["serde_impl"]}
51//! ```
52//!
53//! There is an optional `zlib` feature, that allows the etf to be compressed. In Elixir:
54//!
55//! ```elixir
56//! :erlang.term_to_binary(t, [:compressed])
57//! # or
58//! :erlang.term_to_binary(t, compressed: 6)
59//! ```
60//!
61//! ```toml
62//! erlang-term = {version = "1.1.0", features = ["zlib"]}
63//! ```
64//!
65//! # More examples
66//!
67//! ```
68//! use erlang_term::RawTerm;
69//! use std::iter::FromIterator;
70//!
71//! let map = RawTerm::Map(vec![
72//! (RawTerm::SmallAtom(String::from("test")), RawTerm::SmallTuple(vec![RawTerm::SmallAtom(String::from("ok")), RawTerm::SmallInt(15)])),
73//! (RawTerm::SmallAtom(String::from("another_key")), RawTerm::Binary(b"this is a string".to_vec())),
74//! (RawTerm::SmallAtom(String::from("number")), RawTerm::Float(3.1415.into())),
75//! ]);
76//!
77//! let binary = vec![
78//! 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
79//! ];
80//!
81//! assert_eq!(map.to_bytes(), binary);
82//! ```
83//!
84//! # Use Cases
85//!
86//! - Filter out non-data (such as references and functions) from stored etf files
87//!
88//! - Convert stored etf files to json
89//!
90//! See the [filter example](./examples/filter.rs)
91//!
92
93// http://erlang.org/doc/apps/erts/erl_ext_dist.html#distribution-header
94// https://godoc.org/github.com/goerlang/etf#Term
95
96extern crate nom;
97extern crate num_bigint;
98extern crate num_traits;
99#[cfg(feature = "serde_impl")]
100#[macro_use]
101extern crate serde_derive;
102
103use std::fs::File;
104use std::io::{Read, Result as IoResult};
105
106pub mod consts;
107pub mod dump;
108pub mod parse;
109pub mod raw_term;
110pub mod term;
111
112pub use dump::to_bytes;
113#[cfg(feature = "zlib")]
114pub use dump::to_gzip_bytes;
115pub use parse::from_bytes;
116pub use raw_term::RawTerm;
117pub use term::Term;
118
119pub fn read_binary(input: &str) -> IoResult<Vec<u8>> {
120 let mut file = File::open(input)?;
121 let mut buffer = Vec::new();
122
123 file.read_to_end(&mut buffer)?;
124 Ok(buffer)
125}