-module(thoas). -export([ decode/1, decode/2, encode/1, encode/2, encode_to_iodata/1, encode_to_iodata/2 ]). -export_type([ decode_error/0, decode_options/0, encode_options/0, json_term/0, input_term/0 ]). -type decode_options() :: #{ strings => reference | copy, keys => reference | copy | to_existing_atom | to_atom }. -type encode_options() :: #{ escape => json | unicode | html | javascript }. -type json_term() :: integer() | float() | binary() | boolean() | 'null' | list(json_term()) | #{ binary() => json_term() }. -type input_term() :: integer() | float() | binary() | atom() | calendar:datetime() | calendar:date() | list(input_term()) | list({binary() | atom(), input_term()}) | #{ binary() | atom() => input_term() }. -type decode_error() :: unexpected_end_of_input | {unexpected_byte, binary(), integer()} | {unexpected_sequence, binary(), integer()}. %% Decode JSON into Erlang terms. %% -spec decode(iodata()) -> {ok, json_term()} | {error, decode_error()}. decode(Json) -> decode(Json, #{}). %% Decode JSON into Erlang terms. %% %% # Options %% %% Decoding of keys and string values can be controlled with the options %% `strings` and `keys` respectively. They control how the values are decoded %% into the final Erlang term structure. %% %% - Option values common to both `strings` and `keys` %% - `reference` (default) - when possible thoas tries to create a %% sub-binary into the original %% - `copy` - always copies the sub-binary. This option is especially useful %% when parts of the decoded data will be stored for a long time (in ETS %% or some process state) to avoid keeping the reference to the original %% data %% %% - Option values unique to `keys` %% - `to_existing_atom` - convert keys to atoms if the atom already exists %% - `to_atom` - convert all keys to new or existing atoms. **Caution:** only %% use this if you know you need it, since atoms are not garbage %% collected and there is a hard limit on the amount that can be created. %% Should preferably only be used if the input data is trusted, or in %% short running VM sessions %% -spec decode(iodata(), decode_options()) -> {ok, json_term()} | {error, decode_error()}. decode(Json, Options) when is_map(Options) -> Binary = iolist_to_binary(Json), thoas_decode:decode(Binary, Options). %% Encode Erlang terms into JSON. %% %% Throws on invalid input. %% -spec encode(input_term()) -> binary(). encode(Term) -> encode(Term, #{}). %% Encode Erlang terms into JSON. %% %% Throws on invalid input. %% %% # Options %% %% - `escape` %% - `json` (default) - the regular JSON escaping as defined by RFC 7159. %% - `javascript` - additionally escapes the LINE SEPARATOR (U+2028) and %% PARAGRAPH SEPARATOR (U+2029) characters to make the produced JSON valid %% JavaScript. %% - `html` - similar to `javascript_safe`, but also escapes the / character %% to prevent XSS. %% - `unicode` - escapes all non-ascii characters. %% -spec encode(input_term(), encode_options()) -> binary(). encode(Input, Options) when is_map(Options) -> iolist_to_binary(thoas_encode:encode(Input, Options)). %% Encode Erlang terms into JSON as iodata. %% %% This function should be preferred to encode/2, if the generated JSON will be %% handed over to one of the IO functions or sent over the socket. The Erlang %% runtime is able to leverage vectorised writes and avoid allocating a continuous %% buffer for the whole resulting string, lowering memory use and increasing %% performance. %% %% Throws on invalid input. %% -spec encode_to_iodata(input_term()) -> iodata(). encode_to_iodata(Term) -> encode_to_iodata(Term, #{}). %% Encode Erlang terms into JSON as iodata. %% %% This function should be preferred to encode/2, if the generated JSON will be %% handed over to one of the IO functions or sent over the socket. The Erlang %% runtime is able to leverage vectorised writes and avoid allocating a continuous %% buffer for the whole resulting string, lowering memory use and increasing %% performance. %% %% Throws on invalid input. %% %% # Options %% %% - `escape` %% - `json` (default) - the regular JSON escaping as defined by RFC 7159. %% - `javascript` - additionally escapes the LINE SEPARATOR (U+2028) and %% PARAGRAPH SEPARATOR (U+2029) characters to make the produced JSON valid %% JavaScript. %% - `html` - similar to `javascript_safe`, but also escapes the / character %% to prevent XSS. %% - `unicode` - escapes all non-ascii characters. %% -spec encode_to_iodata(input_term(), encode_options()) -> iodata(). encode_to_iodata(Input, Options) -> thoas_encode:encode(Input, Options).