Skip to main content

src/barrel_lib.erl

%%%-------------------------------------------------------------------
%%% @doc Small shared helpers for wrapping `try ... catch ... end' idioms
%%% that recur across barrel_docdb, so the pattern lives in one place.
%%% @end
%%%-------------------------------------------------------------------
-module(barrel_lib).

-export([safe_fold/1, safe/2, safe_apply/1]).

%% @doc Run a fold that early-terminates by throwing `{stop, Result}'.
%% The fold's callback throws `{stop, Acc}' to stop iteration; this returns
%% either the fold's normal result or the thrown accumulator.
-spec safe_fold(fun(() -> Result)) -> Result.
safe_fold(Fun) ->
    try
        Fun()
    catch
        throw:{stop, Result} -> Result
    end.

%% @doc Run `Fun', returning `Default' on any exception. Best-effort calls
%% where a failure should fall back to a fixed value.
-spec safe(fun(() -> Result), Default) -> Result | Default.
safe(Fun, Default) ->
    try
        Fun()
    catch
        _:_ -> Default
    end.

%% @doc Run `Fun', capturing any failure as `{error, {Class, Reason, Stack}}'.
%% Used to ship worker results back without crashing the caller.
-spec safe_apply(fun(() -> Result)) ->
    {ok, Result} | {error, {atom(), term(), list()}}.
safe_apply(Fun) ->
    try
        {ok, Fun()}
    catch
        Class:Reason:Stack ->
            {error, {Class, Reason, Stack}}
    end.