thrift_runtime_binary (thrift_runtime v0.7.0)

View Source

Thrift binary protocol: value and message codecs as pure functions.

Encoding takes a type descriptor — the same shape the generated struct_info/1, enum_info/1 and function_info/2 introspection functions return — and produces iodata. Decoding consumes a binary and returns the remaining bytes, so callers can stream.

Structs travel as maps keyed by binary field names. On decode, unknown field ids are skipped by wire type, so newer writers stay readable.

Decoding distinguishes more (the binary is a truncated but otherwise valid encoding — read more bytes and retry) from {error, _} (the bytes cannot be a valid encoding). That is what lets the buffered transport parse incrementally off a socket.

Before encoding or decoding, a descriptor is compiled: wire type bytes are precomputed, struct fields are indexed by id in a map, and the required fields are separated out. {ref, Module, Name} schemas are compiled once and cached in persistent_term under their names, so resolving a nested struct is a constant-time lookup. Inline {Kind, Fields} descriptors (such as the function_info/2 params structs) are memoized per process under exact equality — generated descriptors are literals, so the memo hit is a pointer comparison.

Generated types modules ship specialized wire codecs (the encode_<name>_wire/1 / decode_<name>_wire/1 pair plus the binary_codec/1 lookup, emitted by the generator): ref descriptors of named structs dispatch there, so the hot path runs direct binary patterns instead of this engine's compiled-scheme interpreter. The interpreter stays for inline descriptors (RPC param/result structs), hand-written descriptors, and as the fallback when the probe finds no binary_codec/1. Compact and JSON are unaffected — they never consult the probe.

The caches assume generated types modules are never hot-swapped between incompatible versions.

Summary

Functions

Decodes a value of Type from the front of Binary.

Decodes TApplicationException from an EXCEPTION message payload.

Decodes a message envelope.

Encodes Value as Type, or fails with a tagged error.

Encodes TApplicationException as an EXCEPTION message payload.

Encodes a message envelope around Payload (already encoded as a struct).

Skips a value of a raw wire type, used for struct fields with ids the descriptor does not know — and by the generated specialized codecs for the same purpose.

Returns the field descriptors of a struct type descriptor ({struct, {Kind, Fields}}), resolving {struct, {ref, M, N}} through M:struct_info/1.

Types

application_exception()

-type application_exception() :: thrift_runtime_protocol:application_exception().

base_type()

-type base_type() :: thrift_runtime_protocol:base_type().

decode_result(Value)

-type decode_result(Value) :: thrift_runtime_protocol:decode_result(Value).

enum_desc()

-type enum_desc() :: thrift_runtime_protocol:enum_desc().

field_desc()

-type field_desc() :: thrift_runtime_protocol:field_desc().

message_type()

-type message_type() :: thrift_runtime_protocol:message_type().

struct_desc()

-type struct_desc() :: thrift_runtime_protocol:struct_desc().

struct_value()

-type struct_value() :: thrift_runtime_protocol:struct_value().

type_desc()

-type type_desc() :: thrift_runtime_protocol:type_desc().

Functions

decode/2

-spec decode(type_desc(), binary()) -> decode_result(term()).

Decodes a value of Type from the front of Binary.

Returns {ok, Value, Rest}, more when Binary is a truncated valid encoding, or a tagged error.

decode_application_exception(Bin)

-spec decode_application_exception(binary()) -> decode_result(application_exception()).

Decodes TApplicationException from an EXCEPTION message payload.

Unknown fields are skipped per the usual struct rules.

decode_message/1

-spec decode_message(binary()) ->
                        {ok, message_type(), binary(), non_neg_integer(), binary()} |
                        more |
                        {error, term()}.

Decodes a message envelope.

Returns {ok, Type, Name, SeqId, Tail} where Tail is every byte after the seqid (the struct payload plus anything that follows it), more, or a tagged error. The payload length is not part of the envelope, so the struct payload must be decoded from Tail and any trailing bytes ignored.

encode/2

-spec encode(type_desc(), term()) -> {ok, iodata()} | {error, term()}.

Encodes Value as Type, or fails with a tagged error.

encode_application_exception(Message, Code)

-spec encode_application_exception(binary(), non_neg_integer()) -> {ok, iodata()} | {error, term()}.

Encodes TApplicationException as an EXCEPTION message payload.

Codes follow the Thrift specification: 0 unknown, 1 unknown method, 2 invalid message type, 3 wrong method name, 4 bad sequence id, 5 missing result, 6 internal error, 7 protocol error.

encode_message(Type, Name, SeqId, Payload)

-spec encode_message(message_type(), binary(), non_neg_integer(), iodata()) -> iodata().

Encodes a message envelope around Payload (already encoded as a struct).

Always writes the strict format (version 1); decode_message/1 also reads the legacy headerless format.

skip_by_wire/2

-spec skip_by_wire(non_neg_integer(), binary()) -> {ok, binary()} | more | {error, term()}.

Skips a value of a raw wire type, used for struct fields with ids the descriptor does not know — and by the generated specialized codecs for the same purpose.

struct_fields(Desc)

-spec struct_fields(type_desc()) -> [field_desc()].

Returns the field descriptors of a struct type descriptor ({struct, {Kind, Fields}}), resolving {struct, {ref, M, N}} through M:struct_info/1.