OCaml wire format DSL with EverParse 3D output for verified parsers
OCaml 97.4%
Dune 0.3%
Other 2.3%
24 1 0

Clone this repository

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

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

Download tar.gz
README.md

d3t#

Dependent Data Descriptions for binary wire formats.

Overview#

d3t is a GADT-based DSL for describing binary wire formats compatible with EverParse's 3D language. Define your format once, then:

  • Emit EverParse 3D files for verified C parser generation
  • Parse and encode directly in OCaml via bytesrw
  • Generate C stubs for differential testing between OCaml and C implementations

Features#

  • Integer types -- UINT8, UINT16, UINT32, UINT64 (little and big endian)
  • Bitfields -- extract bit ranges from integer bases with constraints
  • Enumerations -- named integer constants with validation
  • Structs -- records with dependent fields and constraints
  • Tagged unions -- casetype with tag-based dispatch
  • Arrays -- fixed-count, byte-sized, and variable-length
  • Constraints -- where clauses with arithmetic and logical expressions
  • Parameterised types -- reusable type templates

Installation#

opam install d3t

Usage#

Defining a Format#

open D3t

(* Simple packet header *)
let header =
  struct_ "Header" [
    field "version" uint8;
    field "length" uint16;
    field "flags" uint8;
  ]

(* With constraints *)
let constrained_header =
  struct_ "ConstrainedHeader" [
    field "version" ~constraint_:Expr.(ref "version" >= int 1) uint8;
    field "length" ~constraint_:Expr.(ref "length" <= int 1500) uint16;
  ]

(* Bitfields *)
let flags =
  struct_ "Flags" [
    field "priority" (bits ~width:3 bf_uint8);
    field "encrypted" (bits ~width:1 bf_uint8);
    field "compressed" (bits ~width:1 bf_uint8);
    field "reserved" (bits ~width:3 bf_uint8);
  ]

(* Tagged union *)
let message =
  casetype "Message" uint8 [
    case 1 (struct_ "Text" [field "text" all_bytes]);
    case 2 (struct_ "Binary" [field "data" (byte_array ~size:(ref "len"))]);
  ]

Generating EverParse 3D#

let m = module_ "Protocol" [
  typedef header;
  typedef constrained_header;
]

let () = print_string (to_3d m)

Output:

module Protocol

typedef struct Header {
  UINT8 version;
  UINT16 length;
  UINT8 flags;
} Header;

typedef struct ConstrainedHeader {
  UINT8 version { version >= 1 };
  UINT16 length { length <= 1500 };
} ConstrainedHeader;

Direct OCaml Parsing#

open D3t

(* Define a record codec *)
let header_codec =
  Record.(
    field "version" uint8 ~get:(fun h -> h.version) ~set:(fun h v -> { h with version = v })
    @@ field "length" uint16 ~get:(fun h -> h.length) ~set:(fun h v -> { h with length = v })
    @@ field "flags" uint8 ~get:(fun h -> h.flags) ~set:(fun h v -> { h with flags = v })
    @@ finish { version = 0; length = 0; flags = 0 }
  )

(* Parse from bytes *)
let parse_header buf =
  decode_record_from_string header_codec buf

(* Encode to bytes *)
let encode_header header =
  encode_record_to_string header_codec header

C Code Generation#

Generate C headers and OCaml FFI stubs for differential testing:

let structs = [header; constrained_header]

(* Generate C runtime header *)
let () = Out_channel.write_all "d3t.h" ~data:(to_c_runtime ())

(* Generate per-struct C headers *)
let () =
  List.iter (fun s ->
    Out_channel.write_all (s.name ^ ".h") ~data:(to_c_header s)
  ) structs

(* Generate OCaml external stubs *)
let () = print_string (to_ml_stubs structs)

Expressions#

The Expr module provides operators for constraints and computations:

open D3t.Expr

(* Arithmetic *)
let size_check = ref "length" - int 4

(* Comparison *)
let valid_version = ref "version" >= int 1 && ref "version" <= int 255

(* Bitwise *)
let masked = ref "flags" land int 0x0F

(* Field references *)
let dynamic_size = ref "header_length" + ref "payload_length"

Architecture#

┌─────────────────┐
│  OCaml DSL      │  Define formats with GADTs
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
    ▼         ▼
┌───────┐ ┌───────────┐
│ to_3d │ │ Record    │  EverParse output or direct parsing
└───┬───┘ │ codecs    │
    │     └─────┬─────┘
    ▼           ▼
┌───────┐ ┌───────────┐
│ .3d   │ │ OCaml     │
│ files │ │ parse/    │
└───┬───┘ │ encode    │
    │     └───────────┘
    ▼
┌───────────────┐
│ EverParse     │  Verified C parser generation
│ (external)    │
└───────────────┘

Dependencies#

Library Purpose
bytesrw Byte stream reading and writing
fmt Pretty printing

References#

Licence#

ISC