エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

ElixirからErlangのASN.1のライブラリを利用するための覚書

Erlang には、 ASN.1 で記述されたデータ構造のコンパイルと、エンコード/レコードをおこなうライブラリが標準で用意されています。

erlang.org

ja.wikipedia.org

かつて通信機器の開発が仕事だったころにあつかっていたことを思い出しつつ、Elixir で利用する方法を記録しておきます。

とはいえ。 ASN.1 については Erlangチュートリアルそのままで、生成した Erlang のモジュールをどのように Elixir から利用するか、というお話がすべてです。

Erlang で ASN.1 のモジュールを生成する

Erlang のマニュアルの Getting Started にしたがって、モジュールを作成します。

まず、定義ファイル People.asn を作成します。

People DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
  Person ::= SEQUENCE {
    name PrintableString,
    location INTEGER {home(0),field(1),roving(2)},
    age INTEGER OPTIONAL
  }
END

次にこれをコンパイルしてモジュールを生成します。 Elixir から Erlang のモジュールや関数を利用するばあいは、特に引数の記述の違いに注意してください。

iex> :asn1ct.compile('People', [:per])
:ok

コンパイルに成功すると、次のファイルが生成されます。

People.asn1db
People.beam
People.erl
People.hrl

生成されたモジュールの関数を Elixir から呼び出す

コンパイルを実行した iex から、あるいは生成されたファイルがあるディレクトリで iex を起動してそこから、次の関数を実行します。

iex> {:ok, bin} = :People.encode(:Person, {:Person, 'Some Name', :roving, 50})
{:ok, <<128, 9, 83, 111, 109, 101, 32, 78, 97, 109, 101, 1, 2, 1, 50>>}

ここで Erlang のモジュール名が People であるため、Elixir からは :People という名前で参照することに注意してください。

続いてエンコードした結果をデコードしてみます。

iex> :People.decode(:Person, bin)
{:ok, {:Person, 'Some Name', :roving, 50}}

元のデータに復元できることが確認できました。

生成されたモジュールを Elixir のプロジェクトに含める

生成した Erlang のモジュールを mix new コマンドで作成する Elixir のプロジェクトで利用できるようにします。

Elixir のプロジェクトでは、コンパイル対象にする Erlang のソースファイルの格納パスが src/ に設定されています。 このため作成したプロジェクト内に src/ というディレクトリを作成し、そこに先に生成された Erlang のソースファイルとヘッダファイルをコピーするだけでモジュールを利用できるようになります。

my_app/
└── src/
    ├── People.erl
    └── People.hrl

コンパイル対象にするパスは、 mix.exsproject/0:erlc_paths を設定することで変更することができます。 くわしくは Mix.Project — Mix v1.11.3mix compile.erlang — Mix v1.11.3 を参照してみてください。

ファイルのコピーができたら、エンコード/デコードができることを確認してみます。

my_app $ iex -S mix

iex(1)> {:ok, bin} = :People.encode(:Person, {:Person, 'Some Name', :roving, 50})
{:ok, <<128, 9, 83, 111, 109, 101, 32, 78, 97, 109, 101, 1, 2, 1, 50>>}

iex(2)> {:ok, result} = :People.decode(:Person, bin)
{:ok, {:Person, 'Some Name', :roving, 50}}