Unsafe v1.0.1 Unsafe View Source
Generate unsafe bindings for Elixir functions.
This library aims to simplify the generation of unsafe function definitions (which here means “functions which can crash”). This is done by code generation at compile time to lessen the bloat in the main source tree, and to remove the cognitive load from the developers.
Generation will create function signatures ending with a !
per
the Elixir standards, and forward the results of the safe function
through to a chosen handler to deal with crashes.
Generation
Registering functions for unsafe generation is as easy as using
the @unsafe
module attribute.
defmodule MyModule do
use Unsafe.Generator,
docs: false
@unsafe [
{ :test, 1, :unwrap }
]
def test(true),
do: { :ok, true }
def test(false),
do: { :ok, false }
defp unwrap({ _, bool }),
do: bool
end
The code above will generate a compile time signature which looks like the following function definition (conceptually):
def test!(arg0) do
unwrap(test(arg0))
end
Thus making all of the following true in practice:
# clearly we keep the main definition
MyModule.test(true) == { :ok, true }
MyModule.test(false) == { :ok, false }
# and the unsafe versions
MyModule.test!(true) == true
MyModule.test!(false) == false
@unsafe
The @unsafe
attribute is used to define which functions should
have their signatures wrapped. Values set against this attribute
must define the function name and arity, with an optional handler.
The following are all valid definitions of the @unsafe
attribute:
# single function binding
@unsafe { :test, 1 }
# many function bindings
@unsafe [ { :test, 1 } ]
# many function arities
@unsafe [ { :test, [ 1, 2 ] } ]
# explicit private (defp) handler definitions
@unsafe [ { :test, 1, :my_handler } ]
# explicit public (def) handler definitions
@unsafe [ { :test, 1, { MyModule, :my_handler } }]
# explicit argument names (for documentation)
@unsafe [ { :test, [ :value ] } ]
It should also be noted that all of the above will accumulate which
means that you can use @unsafe
as many times and in as many places
as you wish inside a module. In addition, you can use @unsafe_binding
in place of @unsafe
if preferred (due to historical reasons).
Options
The use hook accepts options as a way to pass global options to all
@unsafe
attribute hooks inside the current module. These options
will modify the way code is generated.
The existing option set is limited, and is as follows:
docs
- whether or not to enable documentation for the generated functions. By default docs are disabled, so the unsafe functions are hidden from your documentation. If enabled, you should name your arguments instead of providing just an arity.handler
- a default handler to apply to all@unsafe
bindings which do not have an explicit handler set. This is useful if all of your definitions should use the same handler.