<% needs_make? = Enum.any?(@type.params, &Type.needs_make?/1) %>

fn <%= @type.name %>(env: beam.env, argc: c_int, args: [*c] const e.ErlNifTerm) callconv(.C) e.ErlNifTerm {
    beam.context = .<%= context(@concurrency) %>;
    <%= if needs_make? do %>
    var error_info = beam.make_empty_list(env); 
    <% end %>
    <%# TODO: set up a proper allocator variable. %>
    <%= if @leak_check do %>
    var gpa = beam.make_general_purpose_allocator_instance();
    // set the threadlocal beam.allocator
    beam.allocator = gpa.allocator();
    <% else %>
    beam.allocator = beam.raw_allocator;
    <% end %>

    const outer_result = get_result: {
        <%= for {param_type, index} <- Nif.indexed_parameters(@type.params), Type.missing_size?(param_type) do %>
        var size<%= index %>:usize = undefined;
        <% end %>

        const payload_opts = .{
            <%= for {param_type, index} <- Nif.indexed_parameters(@type.params) do %>
            .{
                <%= if needs_make? do %>.error_info = &error_info,<% end %>
                <%= if Type.missing_size?(param_type) do%>.size = &size<%= index %>,<% end %>
                <%= if match?(%Zig.Type.Resource{}, param_type) do%>.root = @This() <% end %>
            },
            <% end %>
        };

        var error_index: u8 = undefined;

        const payload = beam.payload.build(nif.<%= @type.name %>, env, argc, args, &error_index, payload_opts) catch |err| {
            <%= if needs_make? do %>
            return e.enif_raise_exception(env, beam.make(env, .{err, error_index, error_info}, .{}).v);
            <% else %>
            return e.enif_raise_exception(env, beam.make(env, .{err, error_index, beam.make_empty_list(env)}, .{}).v);
            <% end %>
        };

        const cleanup_opts = .{
            <%= for {param_type, index} <- Nif.indexed_parameters(@type.params), do: cleanup_for(@args, param_type, index) %>
        };

        defer beam.payload.cleanup(payload, cleanup_opts);

        const result = @call(.auto, nif.<%= @type.name %>, payload) <%= Nif.maybe_catch(@type.return) %>;

        <%= Type.get_result(@type.return, @return) %>
    };

    <%= if @leak_check do %>
    switch (gpa.deinit()) {
        .ok => 
            return outer_result,
        .leak =>
            return beam.raise_elixir_exception(env, "RuntimeError", .{.message = "memory leak detected in function `<%= @type.name %>/<%= @type.arity %>`"}).v
    }
    <% else %>
    return outer_result;
    <% end %>
}