thrift_runtime_json (thrift_runtime v0.7.0)
View SourceThe Apache Thrift JSON protocol: every value is a JSON document
whose shape carries the Thrift types. A message is the array
[1,"name",type,seqid,payload]; a struct is an object keyed by
field id where every value is a one-key object naming the type
("i32", "str", "rec", ...); a list or set is
["i32",2,1,2], a map ["i32","i32",2,{"1":10}]. Wire-compatible
with the vendored Apache thrift_json_protocol — the golden suite
runs the official JSON client against a JSON server of ours.
One deliberate bend to fit this codebase's pure-codec shape: the
envelope's closing ] is folded into the TOP-LEVEL struct decode
(decode/2 on a struct consumes one optional trailing ]), and
decode_message/1 returns the payload including it. Nested values
are never touched by this — a struct inside a list keeps the ]
that closes the list — but it makes the payload self-contained: the
completeness probe of the buffered transport (an empty descriptor
over the message tail) accounts for every byte exactly, like it
does for the binary and compact protocols.
Struct keys of maps are limited to what a JSON object key can carry:
booleans, integers, doubles and strings. A map keyed by a struct,
list, set or map compiles to {j_unsupported, ...} and both encode
and decode refuse it (the reference implementation would produce
invalid JSON). uuid is likewise uncarryable. Doubles are written
with 16 fractional digits, mirroring the reference round-trip.
Descriptors compile once (see thrift_runtime_binary, the type
vocabulary is shared): inline {struct, {Kind, Fields}} descriptors
are memoized per process under exact equality, {struct, {ref, M, N}} schemas resolve through M:struct_info/1 into a
persistent_term cache. Generated types modules also probe their
specialized json_codec/1 pair — the encode side everywhere, the
decode side carries the non-folding struct body and the bracket
fold is applied by whichever top-level entry calls it (decode/2,
never decode_nested/2). Decoding is
strict — declared fields whose type tag disagrees with the
descriptor are rejected, unknown fields are skipped by their wire
tag, required fields must be present, trailing bytes answer
{error, trailing}.
Summary
Functions
Decodes one value of Type from the front of Binary; the rest comes
back, more marks a valid but truncated input.
Decodes TApplicationException from an EXCEPTION message payload.
Decodes a message envelope.
Non-folding struct decode for refs nested inside containers and struct fields: probes the generated JSON codec pair and falls back to the generic nested decode.
Encodes Value as Type, or fails with a tagged error.
Encodes TApplicationException as an EXCEPTION message payload
(a struct object; the envelope writes the bracket).
Encodes a message envelope around Payload (already encoded as a
struct): the JSON array [1,"name",type,seqid,payload]. The closing
bracket is written here and consumed by the payload's top-level
struct decode on the way back.
Skips one JSON value of wire tag Tag (e.g. <<"i32">>, <<"lst">>)
at the front of Binary; the rest comes back, more marks a valid but
truncated input. Exported for generated JSON codecs: their decode loops
skip unknown struct fields through this function, keeping
skip-on-unknown-field semantics in one place.
Types
-type base_type() :: thrift_runtime_binary:base_type().
-type decode_result(Value) :: thrift_runtime_binary:decode_result(Value).
-type enum_desc() :: thrift_runtime_binary:enum_desc().
-type type_desc() :: thrift_runtime_binary:type_desc().
Functions
-spec decode(thrift_runtime_binary:type_desc(), binary()) -> decode_result(term()).
Decodes one value of Type from the front of Binary; the rest comes
back, more marks a valid but truncated input.
On a struct the optional closing ] of a message envelope is consumed
after the struct proper (see the moduledoc).
-spec decode_application_exception(binary()) -> decode_result(thrift_runtime_binary:application_exception()).
Decodes TApplicationException from an EXCEPTION message payload.
-spec decode_message(binary()) -> {ok, thrift_runtime_binary:message_type(), binary(), non_neg_integer(), binary()} | more | {error, term()}.
Decodes a message envelope.
Returns {ok, Type, Name, SeqId, Payload} where Payload spans the
struct object plus the envelope's closing ] — exactly the bytes the
strict struct decode consumes — then more for a truncated envelope
or a tagged error otherwise.
-spec decode_nested(thrift_runtime_binary:type_desc(), binary()) -> decode_result(term()).
Non-folding struct decode for refs nested inside containers and struct fields: probes the generated JSON codec pair and falls back to the generic nested decode.
The envelope's closing ] is NOT consumed — only the top-level
decode/2 entry points fold it (see the moduledoc).
-spec encode(thrift_runtime_binary:type_desc(), term()) -> {ok, iodata()} | {error, term()}.
Encodes Value as Type, or fails with a tagged error.
-spec encode_application_exception(binary(), non_neg_integer()) -> {ok, iodata()} | {error, term()}.
Encodes TApplicationException as an EXCEPTION message payload
(a struct object; the envelope writes the bracket).
-spec encode_message(thrift_runtime_binary:message_type(), binary(), non_neg_integer(), iodata()) -> iodata().
Encodes a message envelope around Payload (already encoded as a
struct): the JSON array [1,"name",type,seqid,payload]. The closing
bracket is written here and consumed by the payload's top-level
struct decode on the way back.
Skips one JSON value of wire tag Tag (e.g. <<"i32">>, <<"lst">>)
at the front of Binary; the rest comes back, more marks a valid but
truncated input. Exported for generated JSON codecs: their decode loops
skip unknown struct fields through this function, keeping
skip-on-unknown-field semantics in one place.