View Source Exneus (Exneus v0.1.0)

An incredibly flexible and performant JSON parser, generator and formatter for Elixir.

Summary

Functions

Decodes a binary JSON into a term.

Continue parsing a stream of bytes of a JSON value.

End parsing a stream of bytes of a JSON value.

Begin parsing a stream of bytes of a JSON value.

Encodes a term into a binary JSON.

Encode a term into an iodata JSON.

Formats a binary JSON.

Formats a binary JSON.

Minifies a binary JSON.

Minifies a binary JSON.

Types

@type decode_options() :: %{
  optional(:codecs) => [:euneus_decoder.codec()],
  optional(:null) => term(),
  optional(:binary_to_float) => :json.from_binary_fun(),
  optional(:binary_to_integer) => :json.from_binary_fun(),
  optional(:array_start) => :json.array_start_fun(),
  optional(:array_push) => :json.array_push_fun(),
  optional(:array_finish) => :ordered | :reversed | :json.array_finish_fun(),
  optional(:object_start) => :json.object_start_fun(),
  optional(:object_keys) =>
    :binary | :copy | :atom | :existing_atom | :json.from_binary_fun(),
  optional(:object_push) => :json.object_push_fun(),
  optional(:object_finish) =>
    :map | :keyword_list | :reversed_keyword_list | :json.object_finish_fun()
}
@type encode_options() :: %{
  optional(:codecs) => [:euneus_encoder.codec()],
  optional(:codec_callback) => :euneus_encoder.codec_callback(),
  optional(:nulls) => [term()],
  optional(:skip_values) => [term()],
  optional(:key_to_binary) => (term() -> binary()),
  optional(:sort_keys) => boolean(),
  optional(:keyword_lists) => boolean() | {true, is_keyword_list()},
  optional(:escape) => (binary() -> iodata()),
  optional(:encode_integer) => :euneus_encoder.encode(integer()),
  optional(:encode_float) => :euneus_encoder.encode(float()),
  optional(:encode_atom) => :euneus_encoder.encode(atom()),
  optional(:encode_list) => :euneus_encoder.encode(list()),
  optional(:encode_map) => :euneus_encoder.encode(map()),
  optional(:encode_tuple) => :euneus_encoder.encode(tuple()),
  optional(:encode_pid) => :euneus_encoder.encode(pid()),
  optional(:encode_port) => :euneus_encoder.encode(port()),
  optional(:encode_reference) => :euneus_encoder.encode(reference()),
  optional(:encode_term) => :euneus_encoder.encode(term())
}
@type is_keyword_list() :: :euneus_encoder.is_proplist()

Functions

Link to this function

decode!(json, opts \\ %{})

View Source
@spec decode!(json, options) :: term() when json: binary(), options: decode_options()

Decodes a binary JSON into a term.

Example

iex> Exneus.decode!("\"foo\"")
"foo"

Option details

  • codecs - Transforms a JSON binary value into an Erlang term. By returning :next, the next codec will be called, or by returning {:halt, term :: term()}, the term is returned as the value.

    You can use the built-in codecs or your own. Please see the :euneus_decoder.codec/0 type for details.

    Default is [].

    Built-in codecs:

    • timestamp - Transforms an ISO 8601 string with milliseconds into an :erlang.timestamp/0.

      Example:

      iex> Exneus.decode!("\"1970-01-01T00:00:00.000Z\"", %{codecs: [:timestamp]})
      {0, 0, 0}
    • datetime - Transforms an ISO 8601 string into a :calendar.datetime/0.

      Example:

      iex> Exneus.decode!("\"1970-01-01T00:00:00Z\"", %{codecs: [:datetime]})
      {{1970, 01, 01},{00, 00, 00}}
    • ipv4 - Transforms a JSON string into an :inet.ip4_address/0.

      Example:

      iex> Exneus.decode!("\"127.0.0.1\"", %{codecs: [:ipv4]})
      {127, 0, 0, 1}
    • ipv6 - Transforms a JSON string into an :inet.ip6_address/0.

      Example:

      iex> Exneus.decode!("\"::\"", %{codecs: [:ipv6]})
      {0, 0, 0, 0, 0, 0, 0, 0}
      iex> Exneus.decode!("\"::1\"", %{codecs: [:ipv6]})
      {0, 0, 0, 0, 0, 0, 0, 1}
      iex> Exneus.decode!("\"::192.168.42.2\"", %{codecs: [:ipv6]})
      {0, 0, 0, 0, 0, 0, 49320, 10754}
      iex> Exneus.decode!("\"::ffff:192.168.42.2\"", %{codecs: [:ipv6]})
      {0, 0, 0, 0, 0, 65535, 49320, 10754}
      iex> Exneus.decode!("\"3ffe:b80:1f8d:2:204:acff:fe17:bf38\"", %{codecs: [:ipv6]})
      {16382, 2944, 8077, 2, 516, 44287, 65047, 48952}
      iex> Exneus.decode!("\"fe80::204:acff:fe17:bf38\"", %{codecs: [:ipv6]})
      {65152, 0, 0, 0, 516, 44287, 65047, 48952}
    • pid - Transforms a JSON string into an :erlang.pid/0.

      Example:

      iex> Exneus.decode!("\"<0.92.0>\"", %{codecs: [:pid]})
      ...> == :erlang.list_to_pid(~c"<0.92.0>")
      true
    • port - Transforms a JSON string into an :erlang.port/0.

      Example:

      iex> Exneus.decode!("\"#Port<0.1>\"", %{codecs: [:port]})
      ...> == :erlang.list_to_port(~c"#Port<0.1>")
      true
    • reference - Transforms a JSON string into an :erlang.reference/0.

      Example:

      iex> Exneus.decode!("\"#Ref<0.314572725.1088159747.110918>\"", %{codecs: [:reference]})
      ...> == :erlang.list_to_ref(~c"#Ref<0.314572725.1088159747.110918>")
      true

    Custom codec example:

    iex> Exneus.decode!("\"foo\"", %{codecs: [fn ("foo") -> {:halt, :foo} end]})
    :foo
  • null - Defines which term should be considered null.

    Default is nil.

    Example:

    iex> Exneus.decode!("null", %{null: :null})
    :null
  • binary_to_float - Overrides the default binary to float conversion.

  • binary_to_integer - Overrides the default binary to integer conversion..

  • array_start - Overrides the :json.array_start_fun/0 callback.

  • array_push - Overrides the :json.array_push_fun/0 callback.

  • array_finish - Overrides the :json.array_finish_fun/0 callback.

    In addition to the custom function, there are:

    • ordered - Returns the array in the same order as the JSON.

      That's the slower option.

      Example:

      iex> Exneus.decode!("[1,2,3]", %{array_finish: :ordered})
      [1,2,3]
    • reversed - Returns the array in a reversed order.

      That's the faster option.

      Example:

      iex> Exneus.decode!("[1,2,3]", %{array_finish: :reversed})
      [3,2,1]

    Default is ordered.

  • object_start - Overrides the :json.object_start_fun/0 callback.

  • object_keys - Transforms JSON objects key into Erlang term.

    In addition to the custom function, there are:

    Default is binary.

  • object_push - Overrides the :json.object_push_fun/0 callback.

  • object_finish - Overrides the :json.object_finish_fun/0 callback.

    In addition to the custom function, there are:

    • map - Returns the object as a :erlang.map/0.

      That's the slower option.

      Example:

      iex> Exneus.decode!(
      ...>   "{\"a\":\"a\",\"b\":\"b\",\"c\":\"c\"}",
      ...>   %{object_finish: :map}
      ...> )
      %{<<"a">> => <<"a">>,<<"b">> => <<"b">>,<<"c">> => <<"c">>}
    • keyword_list - Returns the object as an ordered keyword/0.

      Example:

      iex> Exneus.decode!(
      ...>   "{\"a\":\"a\",\"b\":\"b\",\"c\":\"c\"}",
      ...>   %{object_finish: :keyword_list}
      ...> )
      [{"a", "a"},{"b", "b"},{"c", "c"}]
    • reversed_keyword_list - Returns the object as a reversed keyword/0.

      That's the faster option.

      Example:

      iex> Exneus.decode!(
      ...>   "{\"a\":\"a\",\"b\":\"b\",\"c\":\"c\"}",
      ...>   %{object_finish: :reversed_keyword_list}
      ...> )
      [{"c", "c"},{"b", "b"},{"a", "a"}]

    Default is map.

Link to this function

decode_stream_continue!(json, state)

View Source
@spec decode_stream_continue!(json, state) :: result
when json: binary() | :end_of_input,
     state: :euneus_decoder.stream_state(),
     result: :euneus_decoder.stream_result()

Continue parsing a stream of bytes of a JSON value.

Example

iex> {:continue, state} = Exneus.decode_stream_start!("{\"foo\":")
iex> Exneus.decode_stream_continue!("1}", state)
{:end_of_input, %{"foo" => 1}}
Link to this function

decode_stream_end!(state)

View Source
@spec decode_stream_end!(state) :: result
when state: :euneus_decoder.stream_state(), result: {:end_of_input, term()}

End parsing a stream of bytes of a JSON value.

Example

iex> {:continue, state} = Exneus.decode_stream_start!("123")
iex> Exneus.decode_stream_end!(state)
{:end_of_input, 123}
Link to this function

decode_stream_start!(json, opts \\ %{})

View Source
@spec decode_stream_start!(json, options) :: result
when json: binary(),
     options: :euneus_decoder.options(),
     result: :euneus_decoder.stream_result()

Begin parsing a stream of bytes of a JSON value.

Link to this function

encode!(term, opts \\ %{})

View Source
@spec encode!(term(), encode_options()) :: iodata()

Encodes a term into a binary JSON.

Example

iex> Exneus.encode!(:foo)
"\"foo\""

Option details

Note

For better visualization and understanding, all options examples use Exneus.encode!/2, which returns a binary.

  • codecs - Transforms tuples into any other Erlang term that will be encoded again into a JSON value. By returning :next, the next codec will be called, or by returning {:halt, term :: term()}, the term will be encoded again.

    You can use the built-in codecs or your own. Please see the :euneus_encoder.codec/0 type for details.

    Default is [].

    Built-in codecs:

    • timestamp - Transforms an :erlang.timestamp/0 into an ISO 8601 string with milliseconds.

      Example:

      iex> Exneus.encode!({0, 0, 0}, %{codecs: [:timestamp]})
      "\"1970-01-01T00:00:00.000Z\""
    • datetime - Transforms a :calendar.datetime/0 into an ISO 8601 string.

      Example:

      iex> Exneus.encode!({{1970, 01, 01}, {00, 00, 00}}, %{codecs: [:datetime]})
      "\"1970-01-01T00:00:00Z\""
    • ipv4 - Transforms an :inet.ip4_address/0 into a JSON string.

      Example:

      iex> Exneus.encode!({127, 0, 0, 1}, %{codecs: [:ipv4]})
      "\"127.0.0.1\""
    • ipv6 - Transforms an :inet.ip6_address/0 into a JSON string.

      Example:

      iex> Exneus.encode!({0, 0, 0, 0, 0, 0, 0, 0}, %{codecs: [:ipv6]})
      "\"::\""
      iex> Exneus.encode!({0, 0, 0, 0, 0, 0, 0, 1}, %{codecs: [:ipv6]})
      "\"::1\""
      iex> Exneus.encode!({0, 0, 0, 0, 0, 0, 49320, 10754}, %{codecs: [:ipv6]})
      "\"::192.168.42.2\""
      iex> Exneus.encode!({0, 0, 0, 0, 0, 65535, 49320, 10754}, %{codecs: [:ipv6]})
      "\"::ffff:192.168.42.2\""
      iex> Exneus.encode!({16382, 2944, 8077, 2, 516, 44287, 65047, 48952}, %{codecs: [:ipv6]})
      "\"3ffe:b80:1f8d:2:204:acff:fe17:bf38\""
      iex> Exneus.encode!({65152, 0, 0, 0, 516, 44287, 65047, 48952}, %{codecs: [:ipv6]})
      "\"fe80::204:acff:fe17:bf38\""
    • records - Transforms records into JSON objects.

      Example:

      iex> Exneus.encode!(
      ...>   # Same as `Record.defrecord(:foo, :bar, :baz)`
      ...>   {:foo, :bar, :baz},
      ...>   %{codecs: [{:records, %{
      ...>       # Use `Record.extract/2` to extract those record informations
      ...>       foo: {[:bar, :baz], 3}
      ...>   }}]}
      ...> )
      if String.to_integer(System.otp_release) >= 26 do
        "{\"bar\":\"bar\",\"baz\":\"baz\"}"
      else
        "{\"baz\":\"baz\",\"bar\":\"bar\"}"
      end

    Custom codec example:

    iex> Exneus.encode!({:foo}, %{codecs: [fn ({:foo}) -> {:halt, :foo} end]})
    "\"foo\""
  • codec_callback - Overrides the default codec resolver.

    Default is euneus_encoder.codec_callback/2.

  • nulls - Defines which values should be encoded as null.

    Default is [nil].

    Example:

    iex> Exneus.encode!([:null, nil, :foo], %{nulls: [:null, nil]})
    "[null,null,\"foo\"]"
  • skip_values - Defines which map values should be ignored. This option permits achieves the same behavior as Javascript, which ignores undefined values of objects.

    Default is [].

    Example:

    iex> Exneus.encode!(
    ...>   %{foo: :bar, bar: :undefined},
    ...>   %{skip_values: [:undefined]}
    ...> )
    "{\"foo\":\"bar\"}"
  • key_to_binary - Overrides the default conversion of map keys to a string.

    Default is :euneus_encoder.key_to_binary/1 .

  • sort_keys - Defines if the object keys should be sorted.

    Default is false.

    Example:

    iex> Exneus.encode!(%{c: :c, a: :a, b: :b}, %{sort_keys: true})
    "{\"a\":\"a\",\"b\":\"b\",\"c\":\"c\"}"
  • keyword_lists - If true, converts keyword_lists into objects.

    Default is false.

    Example:

    iex> Exneus.encode!([:baz, foo: :bar], %{keyword_lists: true})
    "{\"foo\":\"bar\",\"baz\":true}"
    iex> Exneus.encode!(
    ...>     [foo: :bar, baz: true],
    ...>     # Overrides the default is keyword list check:
    ...>     %{keyword_lists: {true, fn ([{_, _} | _]) -> true end}}
    ...> )
    "{\"foo\":\"bar\",\"baz\":true}"
  • escape - Overrides the default string escaping.

    Default is :euneus_encoder.escape/1.

  • encode_integer - Overrides the default integer encoder.

    Default is :euneus_encoder.encode_integer/2.

  • encode_float - Overrides the default float encoder.

    Default is :euneus_encoder.encode_float/2.

  • encode_atom - Overrides the default atom encoder.

    Default is :euneus_encoder.encode_atom/2.

  • encode_list - Overrides the default list encoder.

    Default is :euneus_encoder.encode_list/2.

  • encode_map - Overrides the default map encoder.

    Default is the private function Exneus.encode_map/2.

  • encode_tuple - Overrides the default tuple encoder.

    Default is :euneus_encoder.encode_tuple/2, which raises :unsupported_tuple error.

  • encode_pid - Overrides the default pid encoder.

    Default is :euneus_encoder.encode_pid/2, which raises :unsupported_pid error.

  • encode_port - Overrides the default port encoder.

    Default is :euneus_encoder.encode_port/2, which raises :unsupported_port error.

  • encode_reference - Overrides the default reference encoder.

    Default is :euneus_encoder.encode_reference/2, which raises :unsupported_reference error.

  • encode_term - Overrides the default encoder for unsupported terms, like functions.

    Default is :euneus_encoder.encode_term/2, which raises :unsupported_term error.

Link to this function

encode_to_iodata!(term, opts \\ %{})

View Source
@spec encode_to_iodata!(term(), encode_options()) :: iodata()

Encode a term into an iodata JSON.

Example

iex> Exneus.encode_to_iodata!(:foo)
[?", "foo", ?"]
@spec format(json, options) :: binary()
when json: binary(), options: :euneus_formatter.options()

Formats a binary JSON.

Example

iex> opts = %{
...>   indent_type: :tabs,
...>   indent_width: 1,
...>   spaced_values: true,
...>   crlf: :n
...> }
%{crlf: :n, indent_type: :tabs, indent_width: 1, spaced_values: true}
iex> Exneus.format(" \n{\"foo\"  :  [ true  , \n null ] \n  }  ", opts)
"{\n\t\"foo\": [\n\t\ttrue,\n\t\tnull\n\t]\n}"

Option details

Note

There is no default for any option, all are required.

  • indent_type - Indent using tabs or spaces.

    • tabs - The indent char will be ?\t.

    • spaces - The indent char will be ?\s.

  • indent_width - The indent_type will be copied N times based on it.

  • spaced_values - Defines if keys and values of objects should be spaced by one ?\s char.

  • crlf - Defines the Carriage Return/Line Feed.

    • r - The CRLF will be "\r".

    • n - The CRLF will be "\n".

    • rn - The CRLF will be "\r\n".

    • none - The CRLF will be "".

Link to this function

format_to_iodata(json, opts)

View Source
@spec format_to_iodata(json, options) :: iodata()
when json: binary(), options: :euneus_formatter.options()

Formats a binary JSON.

@spec minify(json) :: binary() when json: binary()

Minifies a binary JSON.

Example

iex> Exneus.minify(" \n{\"foo\"  :  [ true  , \n null ] \n  }  ")
"{\"foo\":[true,null]}"
@spec minify_to_iodata(json) :: iodata() when json: binary()

Minifies a binary JSON.