TBinaryProtocol Spec (derived)

I didn't see a simple description of the TBinaryProtocol specification on the internet, so here is one I derived from reading the java implementation of TBinaryProtocol while implementing the decoder for ThriftFiddle Page design loosely inspired by bsonspec, and EBNF.

ThriftFiddle
symbolexpressioncomment
(request)::=message struct
(reply)::=message (struct)?
message::=msg_strict OR msg_plainIf the signed I32 read is negative, the message was strict. Otherwise, the first 32-bit signed read was the size of the string in msg_plain.
msg_strict::=(VER1 | mtype) string seqidThe first 32-bit value is VER1 bitwise or'd with the message type.
msg_plain::=string mtype seqid
mtype::=0x01CALL
| 0x02REPLY
| 0x03EXCEPTION
| 0x04ONEWAY
seqid::=value(I32)
VER1::=0x8001000032-bit identifier for protocol version 1
struct::=(field)* 0x00 A struct is just an undecorated list of fields, followed by a null byte
field::=type id value(type) A type, id, and value
type::=0x00STOP (designates fields in struct have ended)
| 0x01VOID
| 0x02BOOL
| 0x03BYTE
| 0x04DOUBLE
| 0x06I16
| 0x08I32
| 0x0AI64
| 0x0BSTRING
| 0x0CSTRUCT
| 0x0DMAP
| 0x0ESET
| 0x0FLIST
| 0x10ENUM
id::=value(I16)
size::=value(I32)
value(BOOL)::=0x00 OR 0x01
value(BYTE)::=0x00 - 0xFF
value(DOUBLE)::=IEEE 754 double-precision
value(I16)::=value(BYTE) value(BYTE)(Big endian)
value(I32)::=value(I16) value(I16)(Big endian)
value(I64)::=value(I32) value(I32)(Big endian)
value(STRING)::=size (value(BYTE)){size}
value(STRUCT)::=struct
value(MAP)::=type1 type2 size (value(type1) value(type2)){size}first type is key, second type is value
value(SET)::=type size (value(type)){size}
value(LIST)::=type size (value(type)){size}
value(ENUM)::=value(I32)