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"}