nimler
Nimler is a library for authoring Erlang and Elixir NIFs in the nim programming language. It has mostly complete bindings for the Erlang NIF API and some accessories for making writing NIFs easier, including idiomatic functions for converting between Erlang terms and nim types, and simplifications for using resource objects.
Mostly, Nimler is a minimal, zero-dependency wrapper for Erlang NIF API.
Target | Status |
---|---|
x86_64-linux | |
arm64-linux |
Sample
Positional API sample:
import nimler
using
env: ptr ErlNifEnv
func add(env; a: int, b: int): (ErlAtom, int) {.xnif.} =
(AtomOk, a + b)
func sub(env; a: int, b: int): (ErlAtom, int) {.xnif.} =
(AtomOk, a - b)
func mul(env; a: int, b: int): (ErlAtom, int) {.xnif.} =
(AtomOk, a * b)
exportNifs "Elixir.NifMath", [ add, sub, mul ]
Raw API
If porting a NIF from C, it may be easier to start with the raw API, which retains NIF signature:
import nimler
using
env: ptr ErlNifEnv
argc: cint
argv: ptr UncheckedArray[ErlNifTerm]
func add(env, argc, argv): ErlNifTerm {.nif, arity: 2.} =
# `fromTerm(env, term, to_type)` returns a nim Option.
let a1 = fromTerm(env, argv[0], int).get(0)
let a2 = fromTerm(env, argv[1], int).get(0)
return toTerm(env, a1 + a2)
# Specify external NIF name. In this case, the function is exported as "sub"
# rather than "subnums"
func subnums(env, argc, argv): ErlNifTerm {.nif, arity: 2, name: "sub".} =
let a1 = fromTerm(env, argv[0], int).get(0)
let a2 = fromTerm(env, argv[1], int).get(0)
return toTerm(env, a1 - a2)
# This NIF is tagged with `dirty_cpu`. See the documentation for details on
# using dirty schedulers: https://erlang.org/doc/man/erl_nif.html#functionality
func mul(env, argc, argv): ErlNifTerm {.nif, arity: 2, dirty_cpu.} =
let a1 = fromTerm(env, argv[0], int).get(0)
let a2 = fromTerm(env, argv[1], int).get(1)
return toTerm(env, a1 * a2)
# Optional `{.raises: [].}` pragma is part of nim's effect system. This verifies
# that the NIF does not raise an exception
func div(env, argc, argv): ErlNifTerm {.nif, arity: 2, raises: [].} =
let a1 = fromTerm(env, argv[0], int).get(0)
let a2 = fromTerm(env, argv[1], int)
if a2 == some(0.int):
return enif_make_badarg(env)
return toTerm(env, a1 div a2.unsafeGet())
exportNifs("Elixir.NifMath", [
add,
subnums,
mul,
div
])