Erlang term conversion
Erlang/Elixir terms are represented in nimler with the opaque type ErlNifTerm. Nimler
exposes functions for converting between nim types and Erlang terms.
fromTerm()
fromTerm() produces nim type from ErlNifTerm. fromTerm() returns an Option.
let i_option = env.fromTerm(term, int32)
if i_option.isNone():
# The term was not successfully read into an int32
else:
let i = i_option.get()
# Default value of 0 if term is not read successfully
let ii = env.fromTerm(term, int32).get(0)
toTerm()
toTerm() produces ErlNifTerm from nim type.
let term = env.toTerm(10)
let other_term = env.toTerm(10'i32)
Supported Types
| Erlang | Elixir | Nimler |
|---|---|---|
| Integer | Integer | int, int32, int64, uint, uint32, uint64 |
| Float | Float | float |
| Atom | Atom | distinct string |
| Atom | Atom | bool |
| String | Charlist | seq[char] |
| Bitstring | String | string |
| Binary | Binary | seq[byte] |
| List | List | seq[T] |
| Tuple | Tuple | tuple |
| Map | Map | Table[A, B] |
| PID | PID | ErlPid |
| Term | Term | ErlTerm |
Atoms
let term = env.toTerm(ErlAtom("test"))
# :test
let atom = env.fromTerm(term, ErlAtom).get()
# ErlAtom("test")
Note: The following atom constants are exported from nimler. Note that these are not yet converted to
ErlNifTerm:
AtomOk=ErlAtom("ok")AtomError=ErlAtom("error")AtomTrue=ErlAtom("true")AtomFalse=ErlAtom("false")
Booleans
let term = env.toTerm(true)
# :true
let atom = env.fromTerm(term, bool).get()
# true
Charlists
let term = env.toTerm(@"test")
# 'test'
let lst = env.fromTerm(term, seq[char]).get()
# @['t', 'e', 's', 't']
Strings
Strings follow the Elixir pattern of using Erlang bitstring rather than charlists
let term = env.toTerm("test")
# "test"
let str = env.fromTerm(term, string).get()
# "test"
Binaries
let term = env.toTerm(toOpenArrayByte("test", 0, 3))
# <<116, 101, 115, 116>>
let bin = env.fromTerm(term, seq[byte]).get()
# @[116, 101, 115, 116]
Lists
Elements of seq must be of the same type.
let term = env.toTerm(@[1,2,3])
# [1,2,3]
let lst = env.fromTerm(term, seq[int]).get()
# @[1,2,3]
Tuples
Tuples in nim may contain mixed types.
let term = env.toTerm(("test",1,3.14))
# {"test",1,3.14}
let (a,b,c) = env.fromTerm(term, (string, int, float)).get()
# a="test"
# b=1
# c=3.14
Keyword lists
Keyword lists (lists of {Atom, ErlKeywords. Passing generic object types
to fromTerm() or toTerm() also implies keyword list.
type MyObj = object
a: int
b: float
c: string
let term = toTerm(env, MyObj(a: 1, b: 1.1, c: "test"))
# keyword list: [a: 1, b: 1.1, c: <<"test">>]
let o = fromTerm(env, term, MyObj).get()
# MyObj{a,b,c}
Maps
Maps are represented in nimler with the Table[K, V] type.
import tables
var t = initTable[string, int](4)
t["a"] = 1
t["b"] = 2
let term = env.toTerm(t)
# %{"a" => 1, "b" => 2}
let tt = env.fromTerm(term, Table[string, int]).get()
# {"a": 1, "b": 2}
Opaque terms
Sometimes specifying opaque ErlTerm type is convenient. Example with the
positional nimler API:
func addThing(env: ptr ErlNifEnv, myArg: ErlTerm): ErlTerm {.xnif.} =
# fromTerm(env, myArg, int).get()
# fromTerm(env, myArg, string).get()
# fromTerm(env, myArg, seq[byte]).get()
PIDs
Process IDs are represented in nimler with the ErlPid type.
let pid = fromTerm(env, term, ErlPid).get()
Results
Result tuples have a first element either :ok or :error. Nimler functions env.ok() and env.error() accept varargs.
let ok_term = env.ok(env.toTerm(1), env.toTerm(2))
# {:ok, 1, 2}
let err_term = env.error(env.toTerm("Bad thing"))
# {:error, "Bad thing"}