src/euneus.erl

-module(euneus).

%% --------------------------------------------------------------------
%% API function exports
%% --------------------------------------------------------------------

-export([encode/1]).
-export([encode/2]).
-export([encode_to_iodata/1]).
-export([encode_to_iodata/2]).
-export([decode/1]).
-export([decode/2]).
-export([decode_iodata/1]).
-export([decode_iodata/2]).
-export([decode_stream_start/1]).
-export([decode_stream_start/2]).
-export([decode_stream_continue/2]).
-export([decode_stream_end/1]).
-export([minify/1]).
-export([minify_to_iodata/1]).
-export([format/2]).
-export([format_to_iodata/2]).

%

-ignore_xref([encode/1]).
-ignore_xref([encode/2]).
-ignore_xref([encode_to_iodata/1]).
-ignore_xref([encode_to_iodata/2]).
-ignore_xref([decode/1]).
-ignore_xref([decode/2]).
-ignore_xref([decode_iodata/1]).
-ignore_xref([decode_iodata/2]).
-ignore_xref([decode_stream_start/1]).
-ignore_xref([decode_stream_start/2]).
-ignore_xref([decode_stream_continue/2]).
-ignore_xref([decode_stream_end/1]).
-ignore_xref([minify/1]).
-ignore_xref([minify_to_iodata/1]).
-ignore_xref([format/2]).
-ignore_xref([format_to_iodata/2]).

%% --------------------------------------------------------------------
%% DocTest
%% --------------------------------------------------------------------

-if(?OTP_RELEASE >= 27).
-ifdef(TEST).
-include_lib("doctest/include/doctest.hrl").
-endif.
-endif.

%% --------------------------------------------------------------------
%% API functions
%% --------------------------------------------------------------------

-spec encode(Term) -> binary() when
    Term :: term().
%% @doc Encodes a term into a binary JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:encode(foo).
%% <<"\"foo\"">>
%% '''
encode(Term) ->
    encode(Term, #{}).

-spec encode(Term, Options) -> binary() when
    Term :: term(),
    Options :: euneus_encoder:options().
%% @doc Encodes a term into a binary JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:encode(foo, #{}).
%% <<"\"foo\"">>
%% '''
encode(Term, Opts) ->
    iolist_to_binary(euneus_encoder:encode(Term, Opts)).

-spec encode_to_iodata(Term) -> iodata() when
    Term :: term().
%% @doc Encodes a term into an iodata JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:encode_to_iodata(foo).
%% [$", <<"foo">>, $"]
%% '''
encode_to_iodata(Term) ->
    encode_to_iodata(Term, #{}).

-spec encode_to_iodata(Term, Options) -> iodata() when
    Term :: term(),
    Options :: euneus_encoder:options().
%% @doc Encodes a term into an iodata JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:encode_to_iodata(foo, #{}).
%% [$", <<"foo">>, $"]
%% '''
encode_to_iodata(Term, Opts) ->
    euneus_encoder:encode(Term, Opts).

-spec decode(JSON) -> term() when
    JSON :: binary().
%% @doc Decodes a binary JSON into a term.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:decode(<<"\"foo\"">>).
%% <<"foo">>
%% '''
decode(JSON) ->
    decode(JSON, #{}).

-spec decode(JSON, Options) -> term() when
    JSON :: binary(),
    Options :: euneus_decoder:options().
%% @doc Decodes a binary JSON into a term.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:decode(<<"\"foo\"">>, #{}).
%% <<"foo">>
%% '''
decode(JSON, Opts) ->
    euneus_decoder:decode(JSON, Opts).

-spec decode_iodata(JSON) -> term() when
    JSON :: iodata().
%% @doc Decodes an iodata JSON into a term.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:decode_iodata([$", <<"foo">>, $"]).
%% <<"foo">>
%% '''
decode_iodata(JSON) ->
    decode_iodata(JSON, #{}).

-spec decode_iodata(JSON, Options) -> term() when
    JSON :: iodata(),
    Options :: euneus_decoder:options().
%% @doc Decodes an iodata JSON into a term.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:decode_iodata([$", <<"foo">>, $"], #{}).
%% <<"foo">>
%% '''
decode_iodata(JSON, Opts) ->
    euneus_decoder:decode(iolist_to_binary(JSON), Opts).

-spec decode_stream_start(JSON) -> Result when
    JSON :: binary(),
    Result :: euneus_decoder:stream_result().
%% @equiv decode_stream_start(JSON, #{})
decode_stream_start(JSON) ->
    decode_stream_start(JSON, #{}).

-spec decode_stream_start(JSON, Options) -> Result when
    JSON :: binary(),
    Options :: euneus_decoder:options(),
    Result :: euneus_decoder:stream_result().
%% @equiv euneus_decoder:stream_start(JSON, Options)
%%
%% @doc Begin parsing a stream of bytes of a JSON value.
decode_stream_start(JSON, Opts) ->
    euneus_decoder:stream_start(JSON, Opts).

-spec decode_stream_continue(JSON, State) -> Result when
    JSON :: binary() | end_of_input,
    State :: euneus_decoder:stream_state(),
    Result :: euneus_decoder:stream_result().
%% @equiv euneus_decoder:stream_continue(JSON, State)
%%
%% @doc Continue parsing a stream of bytes of a JSON value.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> begin
%% .. {continue, State} = euneus:decode_stream_start(<<"{\"foo\":">>),
%% .. euneus:decode_stream_continue(<<"1}">>, State)
%% .. end.
%% {end_of_input,#{<<"foo">> => 1}}
%% '''
decode_stream_continue(JSON, State) ->
    euneus_decoder:stream_continue(JSON, State).

-spec decode_stream_end(State) -> Result when
    State :: euneus_decoder:stream_state(),
    Result :: {end_of_input, term()}.
%% @equiv euneus_decoder:stream_continue(end_of_input, State)
%%
%% @doc Ends parsing a stream of bytes of a JSON value.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> begin
%% .. {continue, State} = euneus:decode_stream_start(<<"123">>),
%% .. euneus:decode_stream_end(State)
%% .. end.
%% {end_of_input,123}
%% '''
decode_stream_end(State) ->
    {end_of_input, Term} = euneus_decoder:stream_continue(end_of_input, State),
    {end_of_input, Term}.

-spec minify(JSON) -> binary() when
    JSON :: binary().
%% @equiv iolist_to_binary(minify_to_iodata(JSON))
%%
%% @doc Minifies a binary JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> euneus:minify(<<" \n{\"foo\"  :  [ true  , \n null ] \n  }  ">>).
%% <<"{\"foo\":[true,null]}">>
%% '''
minify(JSON) ->
    iolist_to_binary(minify_to_iodata(JSON)).

-spec minify_to_iodata(JSON) -> iodata() when
    JSON :: binary().
%% @doc Minifies a binary JSON.
minify_to_iodata(JSON) ->
    euneus_formatter:format(JSON, #{
        indent_type => spaces,
        indent_width => 0,
        spaced_values => false,
        crlf => none
    }).

-spec format(JSON, Options) -> binary() when
    JSON :: binary(),
    Options :: euneus_formatter:options().
%% @equiv iolist_to_binary(format(JSON, Options))
%%
%% @doc Formats a binary JSON.
%%
%% <em>Example:</em>
%%
%% ```
%% 1> Opts = #{
%% ..     indent_type => tabs,
%% ..     indent_width => 1,
%% ..     spaced_values => true,
%% ..     crlf => n
%% .. }.
%% #{indent_type => tabs,indent_width => 1,spaced_values => true, crlf => n}
%% 2> euneus:format(<<" \n{\"foo\"  :  [ true  , \n null ] \n  }  ">>, Opts).
%% <<"{\n\t\"foo\": [\n\t\ttrue,\n\t\tnull\n\t]\n}">>
%% '''
format(JSON, Opts) ->
    iolist_to_binary(format_to_iodata(JSON, Opts)).

-spec format_to_iodata(JSON, Options) -> iodata() when
    JSON :: binary(),
    Options :: euneus_formatter:options().
%% @doc Formats a binary JSON.
format_to_iodata(JSON, Opts) ->
    euneus_formatter:format(JSON, Opts).