Current section
Files
Jump to
Current section
Files
lib/firebird/phoenix/fast_helper.ex
defmodule Firebird.Phoenix.FastHelper do
@moduledoc """
Ultra-fast WASM call helper using the SyncNif `call_fast` path.
Drop-in replacement for `WasmHelper.call_string/3` that uses
normal-scheduler + call_unchecked for ~0.5μs overhead per call
(vs ~42μs for Wasmex async).
## Usage
All Phoenix modules (Router, Template, Plug) auto-detect whether
the instance is a SyncNif reference or Wasmex PID and dispatch
to the appropriate helper.
"""
@doc """
Call a WASM function with string input/output via the fastest available path.
- For SyncNif references: uses `call_fast` (~0.5μs overhead)
- For Wasmex PIDs: falls back to `WasmHelper.call_string` (~42μs overhead)
"""
@spec call_string(reference() | pid(), String.t() | atom(), String.t()) ::
{:ok, String.t()} | {:error, term()}
def call_string(instance, function, input) when is_reference(instance) do
function = if is_atom(function), do: Atom.to_string(function), else: function
Firebird.SyncNif.call_fast(instance, function, input)
end
def call_string(instance, function, input) when is_pid(instance) do
Firebird.Phoenix.WasmHelper.call_string(instance, function, input)
end
@doc """
Call a WASM function with an extra integer first argument.
Used for match_method(method_id, path_ptr, path_len, output_ptr).
"""
@spec call_with_int(reference() | pid(), String.t(), integer(), String.t()) ::
{:ok, String.t()} | {:error, term()}
def call_with_int(instance, function, int_arg, input) when is_reference(instance) do
function = if is_atom(function), do: Atom.to_string(function), else: function
Firebird.SyncNif.call_fast_with_int(instance, function, int_arg, input)
end
def call_with_int(instance, function, _int_arg, input) when is_pid(instance) do
# Fall back to string-based call for Wasmex
Firebird.Phoenix.WasmHelper.call_string(instance, function, input)
end
@doc """
Call a compile function: func(input_ptr, input_len) -> count.
"""
@spec call_compile(reference() | pid(), String.t(), String.t()) ::
{:ok, non_neg_integer()} | {:error, term()}
def call_compile(instance, function, input) when is_reference(instance) do
function = if is_atom(function), do: Atom.to_string(function), else: function
Firebird.SyncNif.call_fast_compile(instance, function, input)
end
def call_compile(instance, _function, _input) when is_pid(instance) do
{:error, :use_wasmex_path}
end
@doc """
Call a function that only takes output_ptr: func(output_ptr) -> len.
"""
@spec call_output_only(reference() | pid(), String.t()) ::
{:ok, String.t()} | {:error, term()}
def call_output_only(instance, function) when is_reference(instance) do
function = if is_atom(function), do: Atom.to_string(function), else: function
Firebird.SyncNif.call_fast_output_only(instance, function)
end
def call_output_only(instance, _function) when is_pid(instance) do
{:error, :use_wasmex_path}
end
@doc """
Fused route match: WASM call + result parsing in single NIF call.
Returns {:ok, :not_found} or {:ok, {handler, params_map}}.
Only available for SyncNif references.
"""
@spec call_fast_match(reference(), integer(), String.t()) ::
{:ok, :not_found} | {:ok, {String.t(), map()}} | {:error, term()}
def call_fast_match(instance, method_id, path) when is_reference(instance) do
Firebird.SyncNif.call_fast_match(instance, method_id, path)
end
@doc """
Fused indexed template render: writes values directly to WASM memory.
Eliminates IO.iodata_to_binary overhead (~2-4μs for 60 vars).
Only available for SyncNif references.
"""
@spec call_fast_render_indexed(reference(), list(binary())) ::
{:ok, String.t()} | {:error, term()}
def call_fast_render_indexed(instance, values) when is_reference(instance) do
Firebird.SyncNif.call_fast_render_indexed(instance, values)
end
@doc """
Fused batch indexed template render: renders N value-lists in one NIF call.
Returns {:ok, [rendered_strings]} directly (no binary splitting needed).
Only available for SyncNif references.
"""
@spec call_fast_render_indexed_batch(reference(), list(list(binary()))) ::
{:ok, list(String.t())} | {:error, term()}
def call_fast_render_indexed_batch(instance, values_list) when is_reference(instance) do
Firebird.SyncNif.call_fast_render_indexed_batch(instance, values_list)
end
@doc """
Check if an instance is a SyncNif reference (fast path available).
"""
@spec fast?(reference() | pid()) :: boolean()
def fast?(instance) when is_reference(instance), do: true
def fast?(_instance), do: false
end