Current section
Files
Jump to
Current section
Files
lib/fragment.ex
defmodule RustyJson.Fragment do
@moduledoc """
Represents pre-encoded JSON that should be injected directly into output.
This is compatible with `Jason.Fragment` - if you have existing code using
Jason.Fragment, RustyJson will handle it correctly.
## Usage
# Pre-encode some JSON
fragment = RustyJson.Fragment.new(~s({"already": "encoded"}))
# Include in a larger structure
RustyJson.encode!(%{data: fragment, extra: "field"})
# => {"data":{"already":"encoded"},"extra":"field"}
"""
@type t :: %__MODULE__{encode: iodata() | (term() -> iodata())}
defstruct [:encode]
@doc """
Creates a new fragment from pre-encoded JSON.
"""
@spec new(iodata()) :: t()
def new(data) when is_binary(data) or is_list(data) do
%__MODULE__{encode: data}
end
@spec new((term() -> iodata())) :: t()
def new(encode) when is_function(encode, 1) do
%__MODULE__{encode: encode}
end
@doc """
Creates a validated fragment, ensuring the input is valid JSON.
Raises an error if the input is not valid JSON.
"""
@spec new!(iodata()) :: t()
def new!(data) do
_ = RustyJson.decode!(IO.iodata_to_binary(data))
%__MODULE__{encode: data}
end
end
defimpl RustyJson.Encoder, for: RustyJson.Fragment do
def encode(%RustyJson.Fragment{encode: encode} = fragment) when is_function(encode, 1) do
%{fragment | encode: encode.(nil)}
end
def encode(%RustyJson.Fragment{} = fragment), do: fragment
end