#port #erlang #elixir #interop

erlang_port

Helper library for writing Elixir & Erlang ports in rust

2 unstable releases

Uses old Rust 2015

0.2.0 Oct 14, 2018
0.1.0 Oct 13, 2018

#22 in #elixir

MIT license

20KB
290 lines

erlang_port

A library to ease the process of writing Erlang/Elixir ports using Rust.

Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Prerequisites

You will need a copy of Rust installed. Erlang, Elixir or another BEAM VM would also be useful, as this library is meant to interact with them. Installing these is outside the scope of this document though, so look elsewhere for instructions for that.

Installing

Add erlang_port to your Cargo.toml

erlang_port = "0"

Using

Please see the documentation for usage & examples.

Running the tests

cargo test

Versioning

We use SemVer for versioning. For the versions available, see CHANGELOG.md

License

This project is licensed under the MIT License.


lib.rs:

erlang_port helps make writing Erlang/Elixir ports in Rust easier.

Makes use of the serde_eetf crate to serialize/deserialize rust datatypes into erlang external term format, suitable for passing to/receiving from binary_to_term/term_to_binary

Assuming you are starting your port in packet mode, it's recommended that you use the stdio or nouse_stdio functions inside the main fuction of your application to create an IOPort. You can then use the sender and receiver properties on that IOPort to communicate with Erlang/Elixir.

For example, if you create the following rust program that reads strings from a port and returns them uppercased:

fn lower(mut s: String) -> Result<String, String> {
    s.make_ascii_uppercase();
    Ok(s)
}

fn main() {
   use erlang_port::{PortReceive, PortSend};

  let mut port = unsafe {
      use erlang_port::PacketSize;
      erlang_port::nouse_stdio(PacketSize::Four)
  };

  for string_in in port.receiver.iter() {
      let result = lower(string_in);

      port.sender.reply(result);
  }
}

Then you can call into this port from Elixir:

iex> port =
...>   Port.open({:spawn_executable, port_path}, [
...>       {:packet, 4},
...>       :nouse_stdio,
...>       :binary,
...>       :exit_status
...>   ])
#Port<0.1444>
iex> Port.command(port, :erlang.term_to_binary("hello"))
true
iex> receive do
...>   {^port, {:data, binary}} ->
...>     IO.puts(:erlang.binary_to_term(binary))
...> end
"HELLO"
:ok

If you wish to implement a line-based port or a custom port protocol (using the :stream option) you can do so by implementing the PortSend/PortReceive traits.

Dependencies

~2.3–3MB
~61K SLoC