src/parthenon.erl

%% @author Antoine Gagné <gagnantoine@gmail.com>
%% @copyright 2022 Antoine Gagné
%% @doc Parse Athena structures and schemas.
-module(parthenon).

-export([
    add_schema/2,
    decode/2,
    decode/3
]).

%%%===================================================================
%%% API
%%%===================================================================

-spec add_schema(SchemaName :: atom(), RawSchema :: binary() | string()) -> ok | {error, term()}.
%% @doc
%% Parse the provided schema and register it in the list of available schemas
%% as the specified name.
%% @end
add_schema(SchemaName, RawSchema) ->
    parthenon_schema_server:add_schema(SchemaName, RawSchema).

-spec decode(SchemaName :: atom(), Binary :: binary()) ->
    {ok, parthenon_decode:value()} | {error, term()}.
%% @doc
%% Parse the raw Athena structure with the specified schema.
%% @end
decode(SchemaName, Binary) ->
    parthenon_decode:try_decode(SchemaName, Binary).

-spec decode(SchemaName :: atom(), Binary :: binary(), Options :: [parthenon_decode:option()]) ->
    {ok, parthenon_decode:value()} | {error, term()}.
%% @doc
%% Parse the raw Athena structure with the specified schema and apply the
%% specified options.
%%
%% The supported options are:
%%
%% <ul>
%%   <li>`object_format': Specify the format of the objects.
%%      <ul>
%%        <li>`maps' (default): return objects as maps</li>
%%        <li>`proplists': return objects as proplists</li>
%%        <li>`tuple' will return objects in the `{[{<key>, <value>}]}' format</li>
%%      </ul>
%%   </li>
%%   <li>`key_format': Specify the format of the keys.
%%     <ul>
%%       <li>`atom': return the keys as atoms</li>
%%       <li>`binary' will return the keys as binary.</li>
%%       <li>`existing_atom' (default): return the keys as atoms if they
%%       already exists or return them into binary if they do not</li>
%%     </ul>
%%  </li>
%% </ul>
%%
%% Example usage:
%%
%% ```
%% %% Register the `point' schema into the registry
%% ok = parthenon:add_schema(point, <<"struct<x: int, y: int, z: int>">>).
%%
%% %% Register the `coordinates' schema into the registry
%% ok = parthenon:add_schema(coordinates, <<"array<struct<x: int, y: int, z: int>>">>).
%%
%% %% Decode the `point' structure into a map with binary keys
%% {ok, #{<<"x">> := 3, <<"y">> := 2, <<"z">> := 4}} = parthenon:decode(
%%     point, <<"{x=3, y=2, z=4}">>, [{key_format, binary}, {object_format, maps}]
%% ).
%%
%% %% Decode the `coordinates' array into a list of maps with binary keys
%% {ok, [#{<<"x">> := 3, <<"y">> := 2, <<"z">> := 4}, #{<<"x">> := 5, <<"y">> := 6, <<"z">> := 7}]} = parthenon:decode(
%%      coordinates, <<"[{x=3, y=2, z=4}, {x=5, y=6, z=7}]">>, [
%%          {key_format, binary}, {object_format, maps}
%%      ]
%%  ).
%% '''
%% @end
decode(SchemaName, Binary, Options) ->
    parthenon_decode:try_decode(SchemaName, Binary, Options).

%%%===================================================================
%%% Internal functions
%%%===================================================================