proto_decode() decodes one message to a named list: every scalar type, enums as factors, repeated fields, maps, oneofs, extensions and the well-known types, with limits on size, nesting and memory.
proto_encode() encodes a named list as one message, deterministically, the inverse of proto_decode(); a value of the wrong form fails with a zuproto_type_mismatch naming the field.
proto_decode_df() decodes many messages, or the elements of one message’s repeated field (field =), into a data frame built column by column. proto_read_delimited() and proto_write_delimited() read and write length-delimited streams, in chunks with each.
proto_to_json() and proto_from_json() convert to and from protobuf’s canonical JSON mapping through upb, and to and from R values through zujson when it is installed. proto_unpack_any() decodes an Any, and proto_pack_any() builds one (#60). int64 = "integer64" decodes 64-bit fields as bit64 vectors.
Encoding accepts NaN in double and float fields, writes NULL in a Value field as JSON null, and takes any Timestamp or Duration the binary format allows; the JSON mapping’s narrower ranges are enforced by proto_to_json().
Decoding gives NaN, never NA, for a NaN on the wire, and warns (zuproto_precision_loss) for Timestamp and Duration seconds beyond 2^53.
The memory a decode may use is bounded by what a message of its type can need, so valid input, such as a batch of thousands of small messages, is never refused for it. proto_to_json() bounds every Any it writes by max_depth.
proto_encode() nests as deep as proto_decode() accepts (1000 levels), and refuses strings that are not valid UTF-8, a Date for a Timestamp, and a field given twice. proto_write_delimited() writes back frames whose nested messages hold oneofs. Failures that are no user error are a zuproto_internal_error.