Packages

macula

11.3.0
11.4.0 11.3.1 11.3.0 11.2.0 11.1.0 11.0.0 10.25.0 10.24.0 10.23.0 10.22.0 10.21.0 10.20.3 10.20.2 10.20.0 10.19.2 10.19.1 10.19.0 10.18.0 10.17.0 10.16.0 10.15.0 10.14.5 10.14.4 10.14.2 10.14.1 10.14.0 10.13.2 10.13.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 10.9.0 10.8.0 10.7.0 10.5.8 10.5.7 10.5.6 10.5.5 10.5.4 10.5.3 10.5.2 10.5.1 10.5.0 10.4.0 10.2.0 10.1.1 10.1.0 10.0.2 10.0.1 10.0.0 9.13.8 9.8.2 9.8.1 9.8.0 9.5.0 9.4.0 9.3.1 9.3.0 9.2.0 9.1.1 9.1.0 9.0.0 8.7.0 8.6.0 8.5.0 8.4.1 8.4.0 8.3.0 8.2.0 8.1.0 8.0.2 8.0.1 8.0.0 7.1.0 7.0.0 6.0.0 5.2.2 5.2.1 5.2.0 5.1.0 5.0.0 4.8.0 4.7.1 4.7.0 4.6.0 4.5.0 4.4.10 4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.1 4.3.0 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.1 4.1.0 4.0.0 3.16.0 3.15.3 3.15.2 3.15.1 3.14.0 3.13.0 3.12.1 3.12.0 3.11.1 3.11.0 3.10.3 3.10.2 3.10.1 3.9.0 3.8.0 3.7.0 3.5.0 3.4.0 3.3.0 3.2.0 3.1.0 3.0.0 2.1.1 2.1.0 2.0.0 1.5.2 1.5.1 1.4.30 1.4.29 1.4.28 1.4.27 1.4.26 1.4.25 1.4.24 1.4.23 1.4.22 1.4.21 1.4.20 1.4.19 1.4.18 1.4.17 1.4.16 1.4.15 1.4.14 1.4.13 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.1 1.3.0 1.2.0 1.1.0 1.0.10 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.48.6 0.48.5 0.48.4 0.48.3 0.48.2 0.48.1 0.48.0 0.47.1 0.47.0 0.46.3 0.46.1 0.46.0 0.45.3 0.45.2 0.45.1 0.45.0 0.44.2 0.44.1 0.44.0 0.43.3 0.43.2 0.43.1 0.43.0 0.42.9 0.42.8 0.42.7 0.42.6 0.42.5 0.42.4 0.42.3 0.42.2 0.42.1 0.42.0 0.41.1 0.41.0 0.40.1 0.40.0 0.39.9 0.39.8 0.39.7 0.39.6 0.39.5 0.39.4 0.39.3 0.39.2 0.39.1 0.39.0 0.38.8 0.38.7 0.38.6 0.38.5 0.38.4 0.38.3 0.38.2 0.38.1 0.38.0 0.37.7 0.37.6 0.37.5 0.37.4 0.37.3 0.37.2 0.37.1 0.37.0 0.36.6 0.36.5 0.36.4 0.36.3 0.36.2 0.36.1 0.36.0 0.35.4 0.35.3 0.35.2 0.35.1 0.35.0 0.34.1 0.34.0 0.33.1 0.33.0 0.32.5 0.32.4 0.32.3 0.32.2 0.32.1 0.32.0 0.31.9 0.31.8 0.31.7 0.31.6 0.31.5 0.31.4 0.31.3 0.31.2 0.31.1 0.31.0 0.30.10 0.30.9 0.30.8 0.30.7 0.30.6 0.30.5 0.30.4 0.30.3 0.30.2 0.30.1 0.30.0 0.29.0 0.28.3 0.28.2 0.28.1 0.28.0 0.27.1 0.27.0 0.26.1 0.26.0 0.25.6 0.25.5 0.25.4 0.25.3 0.25.2 0.25.1 0.25.0 0.24.6 0.24.5 0.24.4 0.24.3 0.24.2 0.24.1 0.24.0 0.23.3 0.23.2 0.23.1 0.23.0 0.22.12 0.22.11 0.22.10 0.22.9 0.22.8 0.22.7 0.22.6 0.22.5 0.22.4 0.22.3 0.22.2 0.22.1 0.22.0 0.21.7 0.21.6 0.21.5 0.21.4 0.21.2 0.21.1 0.21.0 0.20.25 0.20.24 0.20.23 0.20.22 0.20.21 0.20.20 0.20.19 0.20.18 0.20.17 0.20.16 0.20.15 0.20.14 0.20.13 0.20.12 0.20.11 0.20.10 0.20.9 0.20.8 0.20.7 0.20.6 0.20.5 0.20.3 0.20.2 0.20.1 0.20.0 0.19.2 0.19.1 0.19.0 0.18.1 0.18.0 0.17.4 0.17.3 0.17.2 0.17.1 0.17.0 0.16.6 0.16.5 0.16.4 0.16.3 0.16.2 0.16.1 0.16.0 0.15.1 0.15.0 0.14.3 0.14.2 0.14.1 0.14.0 0.12.6 0.12.5 0.12.3 0.11.3 0.10.2 0.10.1 0.10.0 0.9.2 0.9.1 0.9.0 0.8.25 0.8.24 0.8.23 0.8.22 0.8.21 0.8.20 0.8.19 0.8.18 0.8.17 0.8.16 0.8.15 0.8.14 0.8.13 0.8.12 0.8.11 0.8.10 0.8.9 0.8.8 0.8.7 0.8.6 0.8.5 0.8.4 0.8.3 0.8.2 0.8.1 0.8.0 0.7.30 0.7.29 0.7.28 0.7.27 0.7.26 0.7.25 0.7.24 0.7.23 0.7.22 0.7.21 0.7.20 0.7.19 0.7.18 0.7.17 0.7.16 0.7.15 0.7.14 0.7.13 0.7.12 0.7.11 0.7.10 0.7.9 0.7.8 0.7.7 0.7.6 0.7.5 0.7.4 0.7.3 0.7.2 0.7.1 0.7.0 0.6.7 0.6.6 0.6.5 0.6.4 0.6.3 0.6.2 0.6.1 0.6.0 0.5.0 0.4.4 0.4.3 0.4.2 0.4.1 0.4.0 0.3.4 0.3.3 0.3.2 0.3.1

Macula HTTP/3 Mesh SDK — connect, subscribe, publish, call, advertise

Current section

Files

Jump to
macula src macula_reason_name.erl
Raw

src/macula_reason_name.erl

%%%-------------------------------------------------------------------
%%% @doc What a reason is called when it leaves this node, and how much
%%% of it the local log prints.
%%%
%%% A peer, a remote caller or a published fact is told a reason's name
%%% and none of its terms. The name is the atom at the reason's head,
%%% such as `killed', `shutdown', `timeout' or `badmatch', looking
%%% through `{error, Reason}' and at most three tuples deep. A reason
%%% with no such atom, or whose atom's name is longer than 64 bytes, has
%%% no name.
%%%
%%% An error a handler answers its caller with may carry the handler's
%%% own text: a binary, or a list whose first 257 elements, or all of them
%%% if fewer, are printable Unicode characters. Only those elements of a
%%% list are looked at, however long it is. The text crosses as at most
%%% 256 bytes of valid UTF-8, cut on a character boundary.
%%%
%%% The whole reason stays on this node, where `logged/2' prints it for
%%% the log to at most 4,096 characters however large it is.
%%% @end
%%%-------------------------------------------------------------------
-module(macula_reason_name).
-export([text/1, reply_text/1, logged/2]).
%% The longest name a reason goes by.
-define(NAME_BYTES, 64).
%% How many tuples deep a reason is looked into for its name.
-define(NAME_DEPTH, 3).
%% The most bytes of a handler's own text that cross to its caller.
-define(REPLY_TEXT_BYTES, 256).
%% What ends a text that was cut.
-define(CUT, <<"...">>).
%% The most characters the log prints of a reason and what came with it.
-define(LOGGED_CHARS, 4096).
%% @doc The reason's name, such as `<<"timeout">>', or `<<"crashed">>'
%% when it has none. This is what an end fact or an abort message says
%% about why something ended.
-spec text(term()) -> binary().
text(Reason) ->
name_or_crashed(name(Reason)).
%% @doc The text a caller is told for an error a handler answered with:
%% the handler's own text when the reason is a binary or a list whose
%% first 257 elements are printable Unicode characters, as at most 256
%% bytes of valid UTF-8; otherwise the reason's name; `error' when the
%% reason has neither.
-spec reply_text(term()) -> {ok, binary()} | error.
reply_text(Text) when is_binary(Text) ->
{ok, within_reply_bytes(Text)};
reply_text(Reason) when is_list(Reason) ->
charlist_text(list_start(Reason, ?REPLY_TEXT_BYTES + 1, []));
reply_text(Reason) ->
name(Reason).
%% @doc `Format' and `Args' printed for the local log, to at most 4,096
%% characters however large the terms in `Args' are. The print stops
%% early on large terms, and what it gives is cut to the bound.
-spec logged(io:format(), [term()]) -> unicode:chardata().
logged(Format, Args) ->
Print = io_lib:format(Format, Args, [{chars_limit, ?LOGGED_CHARS}]),
string:slice(Print, 0, ?LOGGED_CHARS).
name_or_crashed({ok, Name}) -> Name;
name_or_crashed(error) -> <<"crashed">>.
charlist_text({ok, Start}) ->
printable_text(io_lib:printable_unicode_list(Start), Start);
charlist_text(error) ->
error.
printable_text(true, Chars) ->
{ok, within_reply_bytes(unicode:characters_to_binary(Chars))};
printable_text(false, _List) ->
error.
%% A character takes at least one byte, so a list's first 257 elements
%% hold all of its text that can cross and show whether there was more.
%% A list that ends improperly among them is not text.
list_start([Elem | Rest], Left, Start) when Left > 0 ->
list_start(Rest, Left - 1, [Elem | Start]);
list_start([], _Left, Start) ->
{ok, lists:reverse(Start)};
list_start([_ | _], 0, Start) ->
{ok, lists:reverse(Start)};
list_start(_Improper, _Left, _Start) ->
error.
name(Reason) ->
name_text(head_atom(Reason, ?NAME_DEPTH)).
head_atom(Name, _Depth) when is_atom(Name) ->
{ok, Name};
head_atom({error, Reason}, Depth) when Depth > 0 ->
head_atom(Reason, Depth - 1);
head_atom(Reason, Depth) when is_tuple(Reason), tuple_size(Reason) > 0, Depth > 0 ->
head_atom(element(1, Reason), Depth - 1);
head_atom(_Reason, _Depth) ->
error.
name_text({ok, Name}) -> within_name_bytes(atom_to_binary(Name, utf8));
name_text(error) -> error.
within_name_bytes(Text) when byte_size(Text) =< ?NAME_BYTES -> {ok, Text};
within_name_bytes(_Text) -> error.
%% The text whole when it is valid UTF-8 and fits, otherwise its longest
%% valid start that fits with the cut mark after it.
within_reply_bytes(Text) ->
whole_or_cut(Text, valid_start(Text)).
whole_or_cut(Text, Text) when byte_size(Text) =< ?REPLY_TEXT_BYTES ->
Text;
whole_or_cut(Text, _ValidStart) ->
Room = ?REPLY_TEXT_BYTES - byte_size(?CUT),
Start = valid_start(binary:part(Text, 0, min(Room, byte_size(Text)))),
<<Start/binary, ?CUT/binary>>.
valid_start(Bytes) ->
valid(unicode:characters_to_binary(Bytes)).
valid(Valid) when is_binary(Valid) -> Valid;
valid({incomplete, Valid, _Rest}) -> Valid;
valid({error, Valid, _Rest}) -> Valid.