defmodule Unsafe do @moduledoc """ 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. """ end