Protocol Buffers codec for hand-written schemas
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 94.2%
Python 2.8%
Dune 0.7%
Shell 0.4%
Other 1.9%
26 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-protobuf https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-protobuf
git@git.recoil.org:gazagnaire.org/ocaml-protobuf git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-protobuf

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

protobuf#

Protocol Buffers codec for OCaml, for hand-written message schemas.

Define a codec once as a value of type 'a t and use it for both encoding and decoding. No .proto code generation yet — the target use case is speaking specific gRPC or protobuf protocols by hand, where the schema change cadence is low and the combinator definition is short.

Installation#

Install with opam:

$ opam install nox-protobuf

If opam cannot find the package, it may not yet be released in the public opam-repository. Add the overlay repository, then install it:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install nox-protobuf

Usage#

type person = { name : string; age : int32; hobbies : string list }

let person_codec : person Protobuf.t =
  let open Protobuf.Message in
  v (fun name age hobbies -> { name; age; hobbies })
  |> required 1 Protobuf.string ~enc:(fun p -> p.name)
  |> required 2 Protobuf.int32 ~enc:(fun p -> p.age)
  |> repeated 3 Protobuf.string ~enc:(fun p -> p.hobbies)
  |> seal

let wire =
  Protobuf.to_string person_codec
    { name = "Ada"; age = 36l; hobbies = [ "math"; "sewing" ] }

let () =
  match Protobuf.of_string person_codec wire with
  | Ok p -> Printf.printf "%s, %ld, %d hobbies\n" p.name p.age (List.length p.hobbies)
  | Error e -> prerr_endline (Protobuf.Error.to_string e)

Scalar codecs#

Codec OCaml type Wire
int32 int32 varint, signed
int64 int64 varint, signed
uint32 int32 varint, unsigned bit pattern
uint64 int64 varint, unsigned bit pattern
sint32 int32 varint, zig-zag
sint64 int64 varint, zig-zag
fixed32 int32 4 bytes little-endian
fixed64 int64 8 bytes little-endian
sfixed32 int32 4 bytes little-endian, signed
sfixed64 int64 8 bytes little-endian, signed
float float 4 bytes IEEE 754
double float 8 bytes IEEE 754
bool bool varint
string string length-delimited UTF-8
bytes string length-delimited bytes

Field combinators#

The pipeline starts with v ctor and each step adds one field:

  • required n c ~enc — a field at tag n, codec c. Absent decodes as the scalar's default (0, "", false, etc., matching proto3 semantics).
  • optional n c ~enc — the value as 'a option; decoded as None iff the tag is absent.
  • repeated n c ~enc — multiple values (non-packed). Each occurrence of tag n appends to the list.
  • packed n c ~enc — packed repeated: one length-delimited blob holds all values concatenated. Required for numeric repeated fields in proto3.
  • map n kc vc ~enc — a map<K, V> field.
  • oneof ~default ~enc cases — at most one of a set of alternative fields.

Each step takes a builder ('o, 'a -> 'dec) t_ and returns ('o, 'dec) t_; seal closes ('o, 'o) t_ into an 'o Protobuf.t.

Limitations (v0.1)#

  • No .proto code generation. Write codecs by hand.
  • No oneof.
  • No map<K, V>.
  • Unknown fields are discarded on decode (not preserved for re-encode).
  • int32/int64 (not zig-zag) use 10-byte varints for negative values, matching the protobuf spec.