Bebop is a simple and fast serialisation format. You write bebop schemas, and from these bop files different tools produce source code in a number of different languages for serialising and deserialising data to and from the bebop wire format.
This repo builds a tool that generates Go source code from bop files.
One way you could use this is:
go get wellquite.org/bebop/cmd/bebop@latest- Create your bop file, e.g.
protocol.bop Alongside it, create a
generate.gofile, with the following content:package mypackage //go:generate go run wellquite.org/bebop/cmd/bebop -i ./protocol.bop -o ./protocol.go -p my/full/package/name/mypackageThen, whenever you do a
go generate ./...in your project, thisbeboptool will generateprotocol.gofrom yourprotocol.bopschema definition.
What features are supported?
Basically everything I could figure out from the upstream
documentation; apart from the readonly flag which can't really be
implemented in Go.
- All the basic types (including
guidanddate) - All the composite types (arrays and maps, to any nested depth)
- Consts, Enums (including the
flagsflag), Structs, Messages and Unions - Opcodes, deprecated flags, comments
- Imports
Generated API
Imagine a bebop enum, struct, message or union, named
Foo. This tool will generate the following API:
// EncodeBebop writes the value to the writer, serialized as Bebop.
func (*Foo) EncodeBebop(writer io.Writer) error
// DecodeBebop attempts to read Bebop from the reader and to
// deserialize it into the value.
func (*Foo) DecodeBebop(reader io.Reader) error
// MarshalBebop writes the value into the buf, serialized as
// Bebop. The slice of the buf written to is returned. If the buf is too
// small, a new buf is created, written to, and returned.
func (*Foo) MarshalBebop(buf []byte) ([]byte, error)
// UnmarshalBebop attempts to read Bebop from the buf and to
// deserialize it into the value.
func (*Foo) UnmarshalBebop(buf []byte) (int, error)
// SizeBebop returns the number of bytes this value uses when
// serialized to Bebop.
func (*Foo) SizeBebop() int
If you have specified an opcode, there will be:
// [opcode(653)]
func (*Foo) Opcode() uint32
Because I support imports, more functions must be public than one
might like, because they may be needed by other generated code in
other packages. All the functions that are not intended for public use
have comments // Not intended for public use. and all those
functions are named starting Bebop.