# Bento


Bento is a new [Bencoding]( library for Elixir focusing on incredibly fast **speed**
without sacrificing **simplicity**, **completeness**, or **correctness**.

It takes inspiration from [Poison](, a
pure-Elixir JSON library, and uses several techniques found there to achieve this speed:

* Extensive [sub-binary matching](
* A hand-rolled **parser** using several techniques [known to benefit HiPE](
  for native compilation
* [IO list](
* **Single-pass** decoding

Additionally, and unlike some other Elixir bencoding libraries, Bento will also reject all malformed input. This guarantees you're working with a well-formed bencoded file.

Preliminary [benchmarking](#benchmarking) shows that Bento performs over 2x faster when encoding, and at least as fast when decoding, compared to other existing Elixir libraries.

## Installation

Bento is [available in Hex]( The package can be installed by:

  1. Add bento to your list of dependencies in `mix.exs`:

        def deps do
          [{:bento, "~> 0.9.1"}]

  2. Update your dependencies.

        $ mix deps.get

## Usage

Encoding an Elixir data type:

iex> Bento.encode([1, "two", [3]])
{:ok, "li1e3:twoli3eee"}
iex> Bento.encode!(%{"foo" => ["bar", "baz"], "qux" => "norf"})

Decoding a bencoded string:

iex> Bento.decode("li1e3:twoli3eee")
{:ok, [1, "two", [3]]}
iex> Bento.decode!("d3:fool3:bar3:baze3:qux4:norfe")
%{"foo" => ["bar", "baz"], "qux" => "norf"}

Bento is also metainfo-aware and comes with a .torrent decoder out of the box:

iex>!("test/_data/ubuntu-14.04.4-desktop-amd64.iso.torrent") |> Bento.torrent!()
%Bento.Metainfo.Torrent{announce: "",
 "announce-list": [[""],
 comment: "Ubuntu CD", "created by": nil,
 "creation date": 1455826371, encoding: nil,
 info: %Bento.Metainfo.SingleFile{length: 1069547520, md5sum: nil,
  name: "ubuntu-14.04.4-desktop-amd64.iso", "piece length": 524288,
  pieces: <<109, 235, 143, 234, 36, 25, 142, 36, 20, 3, 227, 227, 134, 136, 205, 130, 176, ...>>,
  private: nil}}


Since Bento uses [Poison]('s Decoder module for `.torrent()`, this means it also supports decoding bencoded data into any struct you choose, like so:

defmodule Name do
  defstruct [:family, :given]
iex> Bento.decode!("d6:family4:Folz5:given6:Rodneye", as: %Name{})
%Name{family: "Folz", given: "Rodney"}

## Benchmarking

$ MIX_ENV=bench mix bench

We currently benchmark against: [Bento]( (this project), [bencode](, [Bencodex](, [bencoder](, and [bencoded](

We are aware of, but unable to benchmark against: [exbencode]( (build errors), and [elixir_bencode]( (module name conflicts with Bencode).

PRs that add libraries to the benchmarks are greatly appreciated!

## License