# Copyright(c) 2015-2023 ACCESS CO., LTD. All rights reserved. use Croma defmodule Antikythera.FastJasonEncoder do @moduledoc """ This module converts structures to JSON at low load by avoiding protocol calls. Internally Jason is used. """ alias Croma.Result, as: R alias Antikythera.Time defmodule Wrapper do defstruct item: nil end defimpl Jason.Encoder, for: Wrapper do def encode(%Wrapper{item: item}, opts) do Antikythera.FastJasonEncoder.encode(item, opts) end end defun encode(value :: any) :: R.t(String.t(), Jason.EncodeError.t() | Exception.t()) do Jason.encode(%Wrapper{item: value}) end R.define_bang_version_of(encode: 1) defun encode(value :: any, opts :: Jason.Encode.opts()) :: iodata do [], _ -> "[]" list, opts when is_list(list) -> [?[ | encode_list(list, opts, false)] empty_map, _ when empty_map == %{} -> "{}" %MapSet{map: map}, opts -> encode(Map.keys(map), opts) %DateTime{} = value, _ -> [?", DateTime.to_iso8601(value), ?"] map, opts when is_map(map) -> [?{ | encode_map(Map.to_list(map), opts, false)] value, opts -> if Time.valid?(value) do [?", Time.to_iso_timestamp(value), ?"] else Jason.Encode.value(value, opts) end end defunp encode_map(value :: [tuple], opts :: Jason.Encode.opts(), comma :: boolean) :: iodata do [], _, _ -> '}' [{:__struct__, _v} | tail], opts, comma -> encode_map(tail, opts, comma) list, opts, true -> [?,, encode_map(list, opts, false)] [{k, v} | tail], opts, false -> [encode(k, opts), ?:, encode(v, opts) | encode_map(tail, opts, true)] end defunp encode_list(value :: list, opts :: Jason.Encode.opts(), comma :: boolean) :: iodata do [], _, _ -> ']' list, opts, true -> [?,, encode_list(list, opts, false)] [head | tail], opts, false -> [encode(head, opts) | encode_list(tail, opts, true)] end end