···11(** Micro-benchmark to identify Codec decode allocation sources. *)
2233-open D3t
33+open Wire
4455type r3 = { a : int; b : int; c : int }
66···165165 let _ =
166166 Int32.of_int ((b0 lsl 24) lor (b1 lsl 16) lor (b2 lsl 8) lor b3)
167167 in
168168+ ());
169169+170170+ Printf.printf "\nUInt32 (unboxed on 64-bit):\n";
171171+ measure "Wire.UInt32.get_be" n (fun () ->
172172+ let _ = Wire.UInt32.get_be buf4 0 in
173173+ ());
174174+ measure "byte-by-byte int" n (fun () ->
175175+ let b0 = Bytes.get_uint8 buf4 0 in
176176+ let b1 = Bytes.get_uint8 buf4 1 in
177177+ let b2 = Bytes.get_uint8 buf4 2 in
178178+ let b3 = Bytes.get_uint8 buf4 3 in
179179+ let _ = (b0 lsl 24) lor (b1 lsl 16) lor (b2 lsl 8) lor b3 in
180180+ ());
181181+182182+ Printf.printf "\nUInt63 (unboxed on 64-bit):\n";
183183+ let buf8 = Bytes.create 8 in
184184+ measure "Bytes.get_int64_be (boxed)" n (fun () ->
185185+ let _ = Bytes.get_int64_be buf8 0 in
186186+ ());
187187+ measure "Wire.UInt63.get_be" n (fun () ->
188188+ let _ = Wire.UInt63.get_be buf8 0 in
168189 ())
+27-26
bench/bench_wire_memtrace.ml
···11-(** Memtrace allocation profiling for all 3 d3t codecs.
11+(** Memtrace allocation profiling for all 3 wire codecs.
2233- Run with: MEMTRACE=d3t_clcw.ctf dune exec ./bench_d3t_memtrace.exe -- clcw
44- MEMTRACE=d3t_sp.ctf dune exec ./bench_d3t_memtrace.exe -- space-packet
55- MEMTRACE=d3t_tm.ctf dune exec ./bench_d3t_memtrace.exe -- tm
66- MEMTRACE=d3t_all.ctf dune exec ./bench_d3t_memtrace.exe -- all *)
33+ Run with: MEMTRACE=wire_clcw.ctf dune exec ./bench_wire_memtrace.exe -- clcw
44+ MEMTRACE=wire_sp.ctf dune exec ./bench_wire_memtrace.exe -- space-packet
55+ MEMTRACE=wire_tm.ctf dune exec ./bench_wire_memtrace.exe -- tm
66+ MEMTRACE=wire_all.ctf dune exec ./bench_wire_memtrace.exe -- all *)
7788let iterations = 10_000
99···2424 Bytes.set_int32_be b 0 (Int32.of_int w);
2525 b)
26262727-let clcw_d3t_vals =
2828- Array.map (fun b -> D3t.Codec.decode Clcw_d3t.codec b 0) clcw_bytes
2727+let clcw_wire_vals =
2828+ Array.map (fun b -> Wire.Codec.decode Clcw_wire.codec b 0) clcw_bytes
29293030(** {1 Space Packet test data} *)
3131···3737 Bytes.set_uint16_be b 4 (i mod 256);
3838 b)
39394040-let sp_d3t_vals = Array.map (fun b -> Space_packet_d3t.decode_exn b 0) sp_bytes
4040+let sp_wire_vals =
4141+ Array.map (fun b -> Space_packet_wire.decode_exn b 0) sp_bytes
41424243(** {1 TM test data} *)
4344···5455 Bytes.set_uint16_be b 4 ((1 lsl 14) lor (3 lsl 11) lor (i mod 2048));
5556 b)
56575757-let tm_d3t_vals = Array.map (fun b -> Tm_d3t.decode_exn b 0) tm_bytes
5858+let tm_wire_vals = Array.map (fun b -> Tm_wire.decode_exn b 0) tm_bytes
58595960(** {1 Roundtrip loops} *)
60616162let clcw_roundtrip () =
6263 for i = 0 to Array.length clcw_bytes - 1 do
6363- let t = D3t.Codec.decode Clcw_d3t.codec clcw_bytes.(i) 0 in
6464+ let t = Wire.Codec.decode Clcw_wire.codec clcw_bytes.(i) 0 in
6465 let buf = Bytes.create 4 in
6565- D3t.Codec.encode Clcw_d3t.codec t buf 0
6666+ Wire.Codec.encode Clcw_wire.codec t buf 0
6667 done
67686869let sp_roundtrip () =
6970 for i = 0 to Array.length sp_bytes - 1 do
7070- let t = Space_packet_d3t.decode_exn sp_bytes.(i) 0 in
7171+ let t = Space_packet_wire.decode_exn sp_bytes.(i) 0 in
7172 let buf = Bytes.create 6 in
7272- Space_packet_d3t.encode t buf 0
7373+ Space_packet_wire.encode t buf 0
7374 done
74757576let tm_roundtrip () =
7677 for i = 0 to Array.length tm_bytes - 1 do
7777- let t = Tm_d3t.decode_exn tm_bytes.(i) 0 in
7878+ let t = Tm_wire.decode_exn tm_bytes.(i) 0 in
7879 let buf = Bytes.create 6 in
7979- Tm_d3t.encode t buf 0
8080+ Tm_wire.encode t buf 0
8081 done
81828283(* Decode-only loops *)
8384let clcw_decode () =
8485 for i = 0 to Array.length clcw_bytes - 1 do
8585- let _ = D3t.Codec.decode Clcw_d3t.codec clcw_bytes.(i) 0 in
8686+ let _ = Wire.Codec.decode Clcw_wire.codec clcw_bytes.(i) 0 in
8687 ()
8788 done
88898990let sp_decode () =
9091 for i = 0 to Array.length sp_bytes - 1 do
9191- let _ = Space_packet_d3t.decode_exn sp_bytes.(i) 0 in
9292+ let _ = Space_packet_wire.decode_exn sp_bytes.(i) 0 in
9293 ()
9394 done
94959596let tm_decode () =
9697 for i = 0 to Array.length tm_bytes - 1 do
9797- let _ = Tm_d3t.decode_exn tm_bytes.(i) 0 in
9898+ let _ = Tm_wire.decode_exn tm_bytes.(i) 0 in
9899 ()
99100 done
100101101102(* Encode-only loops *)
102103let clcw_encode () =
103103- for i = 0 to Array.length clcw_d3t_vals - 1 do
104104+ for i = 0 to Array.length clcw_wire_vals - 1 do
104105 let buf = Bytes.create 4 in
105105- D3t.Codec.encode Clcw_d3t.codec clcw_d3t_vals.(i) buf 0
106106+ Wire.Codec.encode Clcw_wire.codec clcw_wire_vals.(i) buf 0
106107 done
107108108109let sp_encode () =
109109- for i = 0 to Array.length sp_d3t_vals - 1 do
110110+ for i = 0 to Array.length sp_wire_vals - 1 do
110111 let buf = Bytes.create 6 in
111111- Space_packet_d3t.encode sp_d3t_vals.(i) buf 0
112112+ Space_packet_wire.encode sp_wire_vals.(i) buf 0
112113 done
113114114115let tm_encode () =
115115- for i = 0 to Array.length tm_d3t_vals - 1 do
116116+ for i = 0 to Array.length tm_wire_vals - 1 do
116117 let buf = Bytes.create 6 in
117117- Tm_d3t.encode tm_d3t_vals.(i) buf 0
118118+ Tm_wire.encode tm_wire_vals.(i) buf 0
118119 done
119120120121let run label decode encode roundtrip =
···132133 done
133134134135let () =
135135- Memtrace.trace_if_requested ~context:"d3t-codecs" ();
136136+ Memtrace.trace_if_requested ~context:"wire-codecs" ();
136137137138 let impl = if Array.length Sys.argv > 1 then Sys.argv.(1) else "all" in
138139139139- Printf.printf "D3t Codec memtrace profiling (%s)\n%!" impl;
140140+ Printf.printf "Wire Codec memtrace profiling (%s)\n%!" impl;
140141 Printf.printf "(%d iterations x 1000 values)\n\n%!" iterations;
141142142143 (match impl with
···11-# This file is generated by dune, edit dune-project instead
22-opam-version: "2.0"
33-synopsis: "Dependent Data Descriptions for binary wire formats"
44-description:
55- "GADT-based DSL for describing binary wire formats with EverParse 3D output. Define your wire format once, then use it for OCaml parsing via bytesrw or emit .3d files for verified C parser generation via EverParse."
66-maintainer: ["Thomas Gazagnaire <thomas@gazagnaire.org>"]
77-authors: ["Thomas Gazagnaire <thomas@gazagnaire.org>"]
88-license: "ISC"
99-homepage: "https://tangled.org/gazagnaire.org/ocaml-d3t"
1010-bug-reports: "https://tangled.org/gazagnaire.org/ocaml-d3t/issues"
1111-depends: [
1212- "dune" {>= "3.21"}
1313- "ocaml" {>= "5.1"}
1414- "bytesrw" {>= "0.1"}
1515- "fmt" {>= "0.9"}
1616- "alcotest" {with-test}
1717- "odoc" {with-doc}
1818-]
1919-build: [
2020- ["dune" "subst"] {dev}
2121- [
2222- "dune"
2323- "build"
2424- "-p"
2525- name
2626- "-j"
2727- jobs
2828- "@install"
2929- "@runtest" {with-test}
3030- "@doc" {with-doc}
3131- ]
3232-]
3333-dev-repo: "git+https://tangled.org/gazagnaire.org/ocaml-d3t"
3434-x-maintenance-intent: ["(latest)"]
+5-5
dune-project
···11(lang dune 3.21)
22(using directory-targets 0.1)
3344-(name d3t)
44+(name wire)
5566(generate_opam_files true)
77···99(authors "Thomas Gazagnaire <thomas@gazagnaire.org>")
1010(maintainers "Thomas Gazagnaire <thomas@gazagnaire.org>")
11111212-(source (tangled gazagnaire.org/ocaml-d3t))
1212+(source (tangled gazagnaire.org/ocaml-wire))
13131414(package
1515- (name d3t)
1616- (synopsis "Dependent Data Descriptions for binary wire formats")
1515+ (name wire)
1616+ (synopsis "Binary wire format DSL with EverParse 3D output")
1717 (description
1818- "GADT-based DSL for describing binary wire formats with EverParse 3D output. \
1818+ "OCaml DSL for describing binary wire formats with EverParse 3D output. \
1919 Define your wire format once, then use it for OCaml parsing via bytesrw or \
2020 emit .3d files for verified C parser generation via EverParse.")
2121 (depends
···11-(** Generic differential testing: OCaml codec vs d3t-generated C code.
11+(** Generic differential testing: OCaml codec vs wire-generated C code.
2233 Each schema needs [c_read] and [c_write] functions (generated by
44- {!D3t.to_c_stubs} and {!D3t.to_ml_stub}). All diff logic is generic over any
55- record codec. *)
44+ {!Wire.to_c_stubs} and {!Wire.to_ml_stub}). All diff logic is generic over
55+ any record codec. *)
6677type 'r schema = {
88 name : string;
···1515}
16161717let schema ~name ~codec ~c_read ~c_write ~equal =
1818- let wire_size = D3t.Codec.wire_size codec in
1818+ let wire_size = Wire.Codec.wire_size codec in
1919 {
2020 name;
2121 c_read;
2222 c_write;
2323 equal;
2424- codec_decode = D3t.Codec.decode codec;
2525- codec_encode = D3t.Codec.encode codec;
2424+ codec_decode = Wire.Codec.decode codec;
2525+ codec_encode = Wire.Codec.encode codec;
2626 wire_size;
2727 }
2828···7979 else Value_mismatch "values differ after full roundtrip"
80808181let roundtrip_struct s buf =
8282- match D3t.read_struct s buf with
8282+ match Wire.read_struct s buf with
8383 | Error e -> Error e
8484- | Ok ps -> D3t.write_struct s ps
8484+ | Ok ps -> Wire.write_struct s ps
85858686type packed_test = {
8787 name : string;
+3-3
lib/diff/diff.mli
···11-(** Generic differential testing: OCaml codec vs d3t-generated C code. *)
11+(** Generic differential testing: OCaml codec vs wire-generated C code. *)
2233val roundtrip_struct :
44- D3t.struct_ -> string -> (string, D3t.parse_error) Stdlib.result
44+ Wire.struct_ -> string -> (string, Wire.parse_error) Stdlib.result
55(** [roundtrip_struct s buf] parses [buf] as struct [s] and re-encodes it.
66 Equivalent to [write_struct s (read_struct s buf)]. *)
77···10101111val schema :
1212 name:string ->
1313- codec:'r D3t.Codec.t ->
1313+ codec:'r Wire.Codec.t ->
1414 c_read:(string -> string option) ->
1515 c_write:(string -> string option) ->
1616 equal:('r -> 'r -> bool) ->
···11-(* D3t: Dependent Data Descriptions for EverParse 3D *)
11+(* Wire: Dependent Data Descriptions for EverParse 3D *)
2233open Result.Syntax
44···1212 let unstage { unstage } = unstage
1313end
14141515+(* UInt32: unboxed on 64-bit (uses int), boxed on 32-bit (uses int32) *)
1616+module UInt32 = struct
1717+ type t = int (* On 64-bit, int is 63 bits - enough for uint32 *)
1818+1919+ let () =
2020+ if Sys.int_size < 32 then
2121+ failwith "Wire.UInt32 requires 64-bit OCaml (int must be >= 32 bits)"
2222+2323+ let get_le buf off =
2424+ let b0 = Bytes.get_uint8 buf off in
2525+ let b1 = Bytes.get_uint8 buf (off + 1) in
2626+ let b2 = Bytes.get_uint8 buf (off + 2) in
2727+ let b3 = Bytes.get_uint8 buf (off + 3) in
2828+ b0 lor (b1 lsl 8) lor (b2 lsl 16) lor (b3 lsl 24)
2929+3030+ let get_be buf off =
3131+ let b0 = Bytes.get_uint8 buf off in
3232+ let b1 = Bytes.get_uint8 buf (off + 1) in
3333+ let b2 = Bytes.get_uint8 buf (off + 2) in
3434+ let b3 = Bytes.get_uint8 buf (off + 3) in
3535+ (b0 lsl 24) lor (b1 lsl 16) lor (b2 lsl 8) lor b3
3636+3737+ let set_le buf off v =
3838+ Bytes.set_uint8 buf off (v land 0xFF);
3939+ Bytes.set_uint8 buf (off + 1) ((v lsr 8) land 0xFF);
4040+ Bytes.set_uint8 buf (off + 2) ((v lsr 16) land 0xFF);
4141+ Bytes.set_uint8 buf (off + 3) ((v lsr 24) land 0xFF)
4242+4343+ let set_be buf off v =
4444+ Bytes.set_uint8 buf off ((v lsr 24) land 0xFF);
4545+ Bytes.set_uint8 buf (off + 1) ((v lsr 16) land 0xFF);
4646+ Bytes.set_uint8 buf (off + 2) ((v lsr 8) land 0xFF);
4747+ Bytes.set_uint8 buf (off + 3) (v land 0xFF)
4848+4949+ let to_int t = t
5050+ let of_int t = t
5151+end
5252+5353+(* UInt63: unboxed on 64-bit (uses int), reads 8 bytes but masks to 63 bits *)
5454+module UInt63 = struct
5555+ type t = int (* 63-bit int on 64-bit platforms *)
5656+5757+ let () =
5858+ if Sys.int_size < 63 then
5959+ failwith "Wire.UInt63 requires 64-bit OCaml (int must be 63 bits)"
6060+6161+ let get_le buf off =
6262+ let b0 = Bytes.get_uint8 buf off in
6363+ let b1 = Bytes.get_uint8 buf (off + 1) in
6464+ let b2 = Bytes.get_uint8 buf (off + 2) in
6565+ let b3 = Bytes.get_uint8 buf (off + 3) in
6666+ let b4 = Bytes.get_uint8 buf (off + 4) in
6767+ let b5 = Bytes.get_uint8 buf (off + 5) in
6868+ let b6 = Bytes.get_uint8 buf (off + 6) in
6969+ let b7 = Bytes.get_uint8 buf (off + 7) in
7070+ b0 lor (b1 lsl 8) lor (b2 lsl 16) lor (b3 lsl 24) lor (b4 lsl 32)
7171+ lor (b5 lsl 40) lor (b6 lsl 48)
7272+ lor ((b7 land 0x7F) lsl 56)
7373+7474+ let get_be buf off =
7575+ let b0 = Bytes.get_uint8 buf off in
7676+ let b1 = Bytes.get_uint8 buf (off + 1) in
7777+ let b2 = Bytes.get_uint8 buf (off + 2) in
7878+ let b3 = Bytes.get_uint8 buf (off + 3) in
7979+ let b4 = Bytes.get_uint8 buf (off + 4) in
8080+ let b5 = Bytes.get_uint8 buf (off + 5) in
8181+ let b6 = Bytes.get_uint8 buf (off + 6) in
8282+ let b7 = Bytes.get_uint8 buf (off + 7) in
8383+ ((b0 land 0x7F) lsl 56)
8484+ lor (b1 lsl 48) lor (b2 lsl 40) lor (b3 lsl 32) lor (b4 lsl 24)
8585+ lor (b5 lsl 16) lor (b6 lsl 8) lor b7
8686+8787+ let set_le buf off v =
8888+ Bytes.set_uint8 buf off (v land 0xFF);
8989+ Bytes.set_uint8 buf (off + 1) ((v lsr 8) land 0xFF);
9090+ Bytes.set_uint8 buf (off + 2) ((v lsr 16) land 0xFF);
9191+ Bytes.set_uint8 buf (off + 3) ((v lsr 24) land 0xFF);
9292+ Bytes.set_uint8 buf (off + 4) ((v lsr 32) land 0xFF);
9393+ Bytes.set_uint8 buf (off + 5) ((v lsr 40) land 0xFF);
9494+ Bytes.set_uint8 buf (off + 6) ((v lsr 48) land 0xFF);
9595+ Bytes.set_uint8 buf (off + 7) ((v lsr 56) land 0x7F)
9696+9797+ let set_be buf off v =
9898+ Bytes.set_uint8 buf off ((v lsr 56) land 0x7F);
9999+ Bytes.set_uint8 buf (off + 1) ((v lsr 48) land 0xFF);
100100+ Bytes.set_uint8 buf (off + 2) ((v lsr 40) land 0xFF);
101101+ Bytes.set_uint8 buf (off + 3) ((v lsr 32) land 0xFF);
102102+ Bytes.set_uint8 buf (off + 4) ((v lsr 24) land 0xFF);
103103+ Bytes.set_uint8 buf (off + 5) ((v lsr 16) land 0xFF);
104104+ Bytes.set_uint8 buf (off + 6) ((v lsr 8) land 0xFF);
105105+ Bytes.set_uint8 buf (off + 7) (v land 0xFF)
106106+107107+ let to_int t = t
108108+ let of_int t = t
109109+end
110110+15111type endian = Little | Big
1611217113(* Expressions *)
···52148and _ typ =
53149 | Uint8 : int typ
54150 | Uint16 : endian -> int typ
5555- | Uint32 : endian -> int32 typ
5656- | Uint64 : endian -> int64 typ
151151+ | Uint32 : endian -> UInt32.t typ
152152+ | Uint63 : endian -> UInt63.t typ
153153+ | Uint64 : endian -> int64 typ (* boxed, for full 64-bit *)
57154 | Bits : { width : int; base : bitfield_base } -> int typ
58155 | Unit : unit typ
59156 | All_bytes : string typ
···153250let uint16be = Uint16 Big
154251let uint32 = Uint32 Little
155252let uint32be = Uint32 Big
253253+let uint63 = Uint63 Little
254254+let uint63be = Uint63 Big
156255let uint64 = Uint64 Little
157256let uint64be = Uint64 Big
158257···318417 | Uint8 -> Fmt.string ppf "UINT8"
319418 | Uint16 e -> Fmt.pf ppf "UINT16%a" pp_endian e
320419 | Uint32 e -> Fmt.pf ppf "UINT32%a" pp_endian e
420420+ | Uint63 e -> Fmt.pf ppf "UINT63%a" pp_endian e
321421 | Uint64 e -> Fmt.pf ppf "UINT64%a" pp_endian e
322422 | Bits { base; _ } -> pp_bitfield_base ppf base
323423 | Unit -> Fmt.string ppf "unit"
···531631 match typ with
532632 | Uint8 -> v
533633 | Uint16 _ -> v
534534- | Uint32 _ ->
535535- (* Unsigned interpretation — on 64-bit OCaml this always succeeds *)
536536- Int32.unsigned_to_int v |> Option.get
634634+ | Uint32 _ -> UInt32.to_int v
635635+ | Uint63 _ -> UInt63.to_int v
537636 | Uint64 _ ->
538637 (* Unsigned interpretation — values >= 2^62 don't fit in OCaml int,
539638 return max_int so constraints [value <= K] fail correctly *)
···734833 | Uint8 -> parse_int dec 1 Bytes.get_uint8 ctx
735834 | Uint16 Little -> parse_int dec 2 Bytes.get_uint16_le ctx
736835 | Uint16 Big -> parse_int dec 2 Bytes.get_uint16_be ctx
737737- | Uint32 Little -> parse_int dec 4 Bytes.get_int32_le ctx
738738- | Uint32 Big -> parse_int dec 4 Bytes.get_int32_be ctx
836836+ | Uint32 Little -> parse_int dec 4 UInt32.get_le ctx
837837+ | Uint32 Big -> parse_int dec 4 UInt32.get_be ctx
838838+ | Uint63 Little -> parse_int dec 8 UInt63.get_le ctx
839839+ | Uint63 Big -> parse_int dec 8 UInt63.get_be ctx
739840 | Uint64 Little -> parse_int dec 8 Bytes.get_int64_le ctx
740841 | Uint64 Big -> parse_int dec 8 Bytes.get_int64_be ctx
741842 | Bits { width; base } -> (
···9171018 Bytes.set_int32_be enc.buf 0 v;
9181019 write_slice enc 4
919102010211021+let write_uint32_le enc v =
10221022+ UInt32.set_le enc.buf 0 v;
10231023+ write_slice enc 4
10241024+10251025+let write_uint32_be enc v =
10261026+ UInt32.set_be enc.buf 0 v;
10271027+ write_slice enc 4
10281028+9201029let write_int64_le enc v =
9211030 Bytes.set_int64_le enc.buf 0 v;
9221031 write_slice enc 8
···9251034 Bytes.set_int64_be enc.buf 0 v;
9261035 write_slice enc 8
927103610371037+let write_uint63_le enc v =
10381038+ UInt63.set_le enc.buf 0 v;
10391039+ write_slice enc 8
10401040+10411041+let write_uint63_be enc v =
10421042+ UInt63.set_be enc.buf 0 v;
10431043+ write_slice enc 8
10441044+9281045let write_string enc s = Bw.write_string enc.writer s
92910469301047let rec encode_with_ctx : type a. ctx -> a typ -> a -> encoder -> ctx =
···9401057 write_uint16_be enc v;
9411058 ctx
9421059 | Uint32 Little ->
943943- write_int32_le enc v;
10601060+ write_uint32_le enc v;
9441061 ctx
9451062 | Uint32 Big ->
946946- write_int32_be enc v;
10631063+ write_uint32_be enc v;
10641064+ ctx
10651065+ | Uint63 Little ->
10661066+ write_uint63_le enc v;
10671067+ ctx
10681068+ | Uint63 Big ->
10691069+ write_uint63_be enc v;
9471070 ctx
9481071 | Uint64 Little ->
9491072 write_int64_le enc v;
···10641187 off + 2
10651188 | Uint32 Little ->
10661189 fun buf off v ->
10671067- Bytes.set_int32_le buf off v;
11901190+ UInt32.set_le buf off v;
10681191 off + 4
10691192 | Uint32 Big ->
10701193 fun buf off v ->
10711071- Bytes.set_int32_be buf off v;
11941194+ UInt32.set_be buf off v;
10721195 off + 4
11961196+ | Uint63 Little ->
11971197+ fun buf off v ->
11981198+ UInt63.set_le buf off v;
11991199+ off + 8
12001200+ | Uint63 Big ->
12011201+ fun buf off v ->
12021202+ UInt63.set_be buf off v;
12031203+ off + 8
10731204 | Uint64 Little ->
10741205 fun buf off v ->
10751206 Bytes.set_int64_le buf off v;
···10971228 | Uint16 Big ->
10981229 fun buf base off -> (Bytes.get_uint16_be buf (base + off), off + 2)
10991230 | Uint32 Little ->
11001100- fun buf base off -> (Bytes.get_int32_le buf (base + off), off + 4)
11011101- | Uint32 Big ->
11021102- fun buf base off -> (Bytes.get_int32_be buf (base + off), off + 4)
12311231+ fun buf base off -> (UInt32.get_le buf (base + off), off + 4)
12321232+ | Uint32 Big -> fun buf base off -> (UInt32.get_be buf (base + off), off + 4)
12331233+ | Uint63 Little ->
12341234+ fun buf base off -> (UInt63.get_le buf (base + off), off + 8)
12351235+ | Uint63 Big -> fun buf base off -> (UInt63.get_be buf (base + off), off + 8)
11031236 | Uint64 Little ->
11041237 fun buf base off -> (Bytes.get_int64_le buf (base + off), off + 8)
11051238 | Uint64 Big ->
···11341267 v
11351268 | Uint32 Little ->
11361269 fun buf base off ->
11371137- let v = Bytes.get_int32_le buf (base + !off) in
12701270+ let v = UInt32.get_le buf (base + !off) in
11381271 off := !off + 4;
11391272 v
11401273 | Uint32 Big ->
11411274 fun buf base off ->
11421142- let v = Bytes.get_int32_be buf (base + !off) in
12751275+ let v = UInt32.get_be buf (base + !off) in
11431276 off := !off + 4;
11441277 v
12781278+ | Uint63 Little ->
12791279+ fun buf base off ->
12801280+ let v = UInt63.get_le buf (base + !off) in
12811281+ off := !off + 8;
12821282+ v
12831283+ | Uint63 Big ->
12841284+ fun buf base off ->
12851285+ let v = UInt63.get_be buf (base + !off) in
12861286+ off := !off + 8;
12871287+ v
11451288 | Uint64 Little ->
11461289 fun buf base off ->
11471290 let v = Bytes.get_int64_le buf (base + !off) in
···11831326 k v
11841327 | Uint32 Little ->
11851328 fun buf base off k ->
11861186- let v = Bytes.get_int32_le buf (base + !off) in
13291329+ let v = UInt32.get_le buf (base + !off) in
11871330 off := !off + 4;
11881331 k v
11891332 | Uint32 Big ->
11901333 fun buf base off k ->
11911191- let v = Bytes.get_int32_be buf (base + !off) in
13341334+ let v = UInt32.get_be buf (base + !off) in
11921335 off := !off + 4;
11931336 k v
13371337+ | Uint63 Little ->
13381338+ fun buf base off k ->
13391339+ let v = UInt63.get_le buf (base + !off) in
13401340+ off := !off + 8;
13411341+ k v
13421342+ | Uint63 Big ->
13431343+ fun buf base off k ->
13441344+ let v = UInt63.get_be buf (base + !off) in
13451345+ off := !off + 8;
13461346+ k v
11941347 | Uint64 Little ->
11951348 fun buf base off k ->
11961349 let v = Bytes.get_int64_le buf (base + !off) in
···14451598 | Uint8 -> fun buf base -> Bytes.get_uint8 buf (base + field_off)
14461599 | Uint16 Little -> fun buf base -> Bytes.get_uint16_le buf (base + field_off)
14471600 | Uint16 Big -> fun buf base -> Bytes.get_uint16_be buf (base + field_off)
14481448- | Uint32 Little -> fun buf base -> Bytes.get_int32_le buf (base + field_off)
14491449- | Uint32 Big -> fun buf base -> Bytes.get_int32_be buf (base + field_off)
16011601+ | Uint32 Little -> fun buf base -> UInt32.get_le buf (base + field_off)
16021602+ | Uint32 Big -> fun buf base -> UInt32.get_be buf (base + field_off)
16031603+ | Uint63 Little -> fun buf base -> UInt63.get_le buf (base + field_off)
16041604+ | Uint63 Big -> fun buf base -> UInt63.get_be buf (base + field_off)
14501605 | Uint64 Little -> fun buf base -> Bytes.get_int64_le buf (base + field_off)
14511606 | Uint64 Big -> fun buf base -> Bytes.get_int64_be buf (base + field_off)
14521607 | Where { inner; _ } -> build_field_reader inner field_off
···1648180316491804(* ==================== EverParse FFI Helpers ==================== *)
1650180516511651-(* NOTE: d3t does NOT generate C parsing code. C parsers come from EverParse.
18061806+(* NOTE: wire does NOT generate C parsing code. C parsers come from EverParse.
16521807 This section provides helpers for generating OCaml FFI stubs that call
16531808 EverParse-generated C code.
1654180916551810 Workflow:
16561656- 1. Define schema in OCaml using d3t
18111811+ 1. Define schema in OCaml using wire
16571812 2. Generate .3d file with to_3d
16581813 3. Run EverParse to generate C parser (.h with struct + read/write)
16591814 4. Use to_c_stubs to generate OCaml FFI bindings to call EverParse C *)
···16881843 | _ -> None)
16891844 (Some 0) s.fields
1690184516911691-(** OCaml type name for a d3t type (for generated external declarations). *)
18461846+(** OCaml type name for a wire type (for generated external declarations). *)
16921847let rec ml_type_of : type a. a typ -> string = function
16931848 | Uint8 -> "int"
16941849 | Uint16 _ -> "int"
···17431898let c_stub_read ppf (s : struct_) fields =
17441899 let n = List.length fields in
17451900 let has_boxed = List.exists (fun (Named (_, typ)) -> is_boxed typ) fields in
17461746- Fmt.pf ppf "CAMLprim value caml_d3t_%s_read(value v_buf) {@\n" s.name;
19011901+ Fmt.pf ppf "CAMLprim value caml_wire_%s_read(value v_buf) {@\n" s.name;
17471902 Fmt.pf ppf " CAMLparam1(v_buf);@\n";
17481903 if has_boxed then Fmt.pf ppf " CAMLlocal3(v_some, v_tuple, v_tmp);@\n"
17491904 else Fmt.pf ppf " CAMLlocal2(v_some, v_tuple);@\n";
···17721927 EverParse-generated [Name_write] function. *)
17731928let c_stub_write ppf (s : struct_) fields =
17741929 let sz = match wire_size_of_struct s with Some n -> n | None -> 4096 in
17751775- Fmt.pf ppf "CAMLprim value caml_d3t_%s_write(value v_tuple) {@\n" s.name;
19301930+ Fmt.pf ppf "CAMLprim value caml_wire_%s_write(value v_tuple) {@\n" s.name;
17761931 Fmt.pf ppf " CAMLparam1(v_tuple);@\n";
17771932 Fmt.pf ppf " CAMLlocal2(v_some, v_str);@\n";
17781933 Fmt.pf ppf " %s val;@\n" s.name;
···17951950 [Name_write].
1796195117971952 For each struct [Foo] with fields [a : t1, b : t2, ...], generates:
17981798- - [caml_d3t_Foo_read(v_buf)] returning [(t1 * t2 * ...) option]
17991799- - [caml_d3t_Foo_write(v_tuple)] taking [(t1 * t2 * ...)] and returning
19531953+ - [caml_wire_Foo_read(v_buf)] returning [(t1 * t2 * ...) option]
19541954+ - [caml_wire_Foo_write(v_tuple)] taking [(t1 * t2 * ...)] and returning
18001955 [string option].
1801195618021957 The generated code expects EverParse headers to be available:
···18051960 let buf = Buffer.create 4096 in
18061961 let ppf = Format.formatter_of_buffer buf in
18071962 Fmt.pf ppf
18081808- "/* d3t_stubs.c - OCaml FFI stubs for EverParse-generated C */@\n@\n";
19631963+ "/* wire_stubs.c - OCaml FFI stubs for EverParse-generated C */@\n@\n";
18091964 Fmt.pf ppf "#include <caml/mlvalues.h>@\n";
18101965 Fmt.pf ppf "#include <caml/memory.h>@\n";
18111966 Fmt.pf ppf "#include <caml/alloc.h>@\n";
···18361991let to_ml_stubs (structs : struct_ list) =
18371992 let buf = Buffer.create 256 in
18381993 let ppf = Format.formatter_of_buffer buf in
18391839- Fmt.pf ppf "(* Generated by d3t (do not edit) *)@\n@\n";
19941994+ Fmt.pf ppf "(* Generated by wire (do not edit) *)@\n@\n";
18401995 List.iter
18411996 (fun (s : struct_) ->
18421997 let fields = named_fields s in
···18462001 in
18472002 Fmt.pf ppf "module %s = struct@\n" s.name;
18482003 Fmt.pf ppf " external read : string -> (%s) option@\n" tuple_type;
18491849- Fmt.pf ppf " = \"caml_d3t_%s_read\"@\n" s.name;
20042004+ Fmt.pf ppf " = \"caml_wire_%s_read\"@\n" s.name;
18502005 Fmt.pf ppf " external write : (%s) -> string option@\n" tuple_type;
18511851- Fmt.pf ppf " = \"caml_d3t_%s_write\"@\n" s.name;
20062006+ Fmt.pf ppf " = \"caml_wire_%s_write\"@\n" s.name;
18522007 Fmt.pf ppf "end@\n@\n")
18532008 structs;
18542009 Format.pp_print_flush ppf ();
···18702025(** Generate a flat OCaml stub module for a single struct. Produces a file with
18712026 [type t] and [external read/write] declarations:
18722027 {[
18731873- (* Generated by d3t *)
20282028+ (* Generated by wire *)
18742029 type t = int * int * int32
1875203018761876- external read : string -> t option = "caml_d3t_Foo_read"
18771877- external write : t -> string option = "caml_d3t_Foo_write"
20312031+ external read : string -> t option = "caml_wire_Foo_read"
20322032+ external write : t -> string option = "caml_wire_Foo_write"
18782033 ]} *)
18792034let to_ml_stub (s : struct_) =
18802035 let buf = Buffer.create 256 in
···18842039 String.concat " * "
18852040 (List.map (fun (Named (_, typ)) -> ml_type_of typ) fields)
18862041 in
18871887- Fmt.pf ppf "(* Generated by d3t (do not edit) *)@\n@\n";
20422042+ Fmt.pf ppf "(* Generated by wire (do not edit) *)@\n@\n";
18882043 Fmt.pf ppf "type t = %s@\n@\n" tuple_type;
18892044 Fmt.pf ppf "external read : string -> t option@\n";
18901890- Fmt.pf ppf " = \"caml_d3t_%s_read\"@\n@\n" s.name;
20452045+ Fmt.pf ppf " = \"caml_wire_%s_read\"@\n@\n" s.name;
18912046 Fmt.pf ppf "external write : t -> string option@\n";
18921892- Fmt.pf ppf " = \"caml_d3t_%s_write\"@\n" s.name;
20472047+ Fmt.pf ppf " = \"caml_wire_%s_write\"@\n" s.name;
18932048 Format.pp_print_flush ppf ();
18942049 Buffer.contents buf
18952050
+51-15
lib/wire.mli
···11(** Dependent Data Descriptions for binary wire formats.
2233- D3t is a GADT-based DSL for describing binary wire formats compatible with
33+ Wire is a GADT-based DSL for describing binary wire formats compatible with
44 EverParse's 3D language. Define your format once, then:
5566 - Use {!to_3d} to emit EverParse 3D format for verified C parser generation
···4646 val unstage : 'a t -> 'a
4747 (** [unstage t] extracts the value from a staged computation. This is where
4848 the cost of specialization is paid. *)
4949+end
5050+5151+(** {1 Unboxed Integer Types}
5252+5353+ On 64-bit platforms, these types are unboxed (immediate) for zero-allocation
5454+ parsing. On 32-bit platforms, the module will fail at initialization. *)
5555+5656+module UInt32 : sig
5757+ type t = int
5858+ (** Unsigned 32-bit integer. Unboxed on 64-bit platforms (fits in 63-bit int).
5959+ *)
6060+6161+ val get_le : bytes -> int -> t
6262+ val get_be : bytes -> int -> t
6363+ val set_le : bytes -> int -> t -> unit
6464+ val set_be : bytes -> int -> t -> unit
6565+ val to_int : t -> int
6666+ val of_int : int -> t
6767+end
6868+6969+module UInt63 : sig
7070+ type t = int
7171+ (** Unsigned 63-bit integer. Reads 8 bytes but masks to 63 bits. *)
7272+7373+ val get_le : bytes -> int -> t
7474+ val get_be : bytes -> int -> t
7575+ val set_le : bytes -> int -> t -> unit
7676+ val set_be : bytes -> int -> t -> unit
7777+ val to_int : t -> int
7878+ val of_int : int -> t
4979end
50805181(** {1 Endianness} *)
···210240val uint16be : int typ
211241(** Unsigned 16-bit integer, big-endian. *)
212242213213-val uint32 : int32 typ
214214-(** Unsigned 32-bit integer, little-endian. *)
243243+val uint32 : UInt32.t typ
244244+(** Unsigned 32-bit integer, little-endian. Unboxed on 64-bit. *)
215245216216-val uint32be : int32 typ
217217-(** Unsigned 32-bit integer, big-endian. *)
246246+val uint32be : UInt32.t typ
247247+(** Unsigned 32-bit integer, big-endian. Unboxed on 64-bit. *)
248248+249249+val uint63 : UInt63.t typ
250250+(** Unsigned 63-bit integer, little-endian. Unboxed on 64-bit. Reads 8 bytes. *)
251251+252252+val uint63be : UInt63.t typ
253253+(** Unsigned 63-bit integer, big-endian. Unboxed on 64-bit. Reads 8 bytes. *)
218254219255val uint64 : int64 typ
220220-(** Unsigned 64-bit integer, little-endian. *)
256256+(** Unsigned 64-bit integer, little-endian. Boxed (full 64-bit precision). *)
221257222258val uint64be : int64 typ
223223-(** Unsigned 64-bit integer, big-endian. *)
259259+(** Unsigned 64-bit integer, big-endian. Boxed (full 64-bit precision). *)
224260225261(** {2 Bitfields} *)
226262···643679 type packet = { version : int; length : int }
644680645681 let codec =
646646- let open D3t.Codec in
682682+ let open Wire.Codec in
647683 record "Packet" (fun version length -> { version; length })
648684 |+ field "version" uint8 (fun p -> p.version)
649685 |+ field "length" uint16be (fun p -> p.length)
650686 |> seal
651687652652- let decode = D3t.Codec.decode codec
653653- let encode = D3t.Codec.encode codec
654654- let struct_ = D3t.Codec.to_struct codec
688688+ let decode = Wire.Codec.decode codec
689689+ let encode = Wire.Codec.encode codec
690690+ let struct_ = Wire.Codec.to_struct codec
655691 ]} *)
656692657693module Codec : sig
···703739 Returns [None] if the struct contains variable-length fields. *)
704740705741val ml_type_of : 'a typ -> string
706706-(** [ml_type_of typ] returns the OCaml type name for a d3t type (e.g., ["int"],
742742+(** [ml_type_of typ] returns the OCaml type name for a wire type (e.g., ["int"],
707743 ["int32"], ["int64"]). *)
708744709745val to_c_stubs : struct_ list -> string
710746(** [to_c_stubs structs] generates a C file with OCaml FFI stubs for
711747 differential roundtrip testing. For each struct [Foo], it generates a
712712- [caml_d3t_roundtrip_foo] function that reads bytes via [Foo_read], writes
748748+ [caml_wire_roundtrip_foo] function that reads bytes via [Foo_read], writes
713749 them back via [Foo_write], and returns the result as an OCaml
714750 [string option]. *)
715751···732768 {[
733769 type t = int * int * int32
734770735735- external read : string -> t option = "caml_d3t_Foo_read"
736736- external write : t -> string option = "caml_d3t_Foo_write"
771771+ external read : string -> t option = "caml_wire_Foo_read"
772772+ external write : t -> string option = "caml_wire_Foo_write"
737773 ]} *)
738774739775(** {1 Struct-level Read/Write}
+27-12
test/diff/dune
···11-; Differential testing: OCaml d3t vs EverParse C parsers
11+; Differential testing: OCaml wire vs EverParse C parsers
22;
33; Workflow:
44; 1. gen_c generates random schemas as .3d files
···1010(library
1111 (name schema)
1212 (modules schema)
1313- (libraries d3t))
1313+ (libraries wire))
14141515; Generate .3d files from OCaml schemas
1616···2626 (run ./gen_schemas.exe)))
27272828; Generate .3d files from random schemas into schemas/ directory
2929+; Also generates stubs.c, stubs.ml, diff_test.ml and schemas/dune
29303031(executable
3132 (name gen_c)
3233 (modules gen_c)
3333- (libraries d3t unix))
3434+ (libraries wire unix))
34353536(rule
3636- (target
3737- (dir schemas))
3737+ (targets
3838+ (dir schemas)
3939+ stubs.c
4040+ stubs.ml
4141+ diff_test.ml)
3842 (deps gen_c.exe)
3943 (action
4044 (run ./gen_c.exe schemas 100)))
41454242-; Run EverParse 3d to generate C from .3d files
4343-; Requires EverParse to be installed at ~/.local/everparse
4646+; Differential test: compile C stubs (includes EverParse generated C)
4747+; stubs.c #includes the C files from schemas/
4848+4949+(library
5050+ (name stubs)
5151+ (modules stubs)
5252+ (foreign_stubs
5353+ (language c)
5454+ (names stubs)
5555+ (flags :standard -I schemas)))
5656+5757+(executable
5858+ (name diff_test)
5959+ (modules diff_test)
6060+ (libraries stubs))
44614562(rule
4646- (alias 3d)
4747- (deps
4848- (source_tree schemas))
6363+ (alias diff)
6464+ (deps diff_test.exe)
4965 (action
5050- (bash
5151- "cd schemas && for f in *.3d; do ~/.local/everparse/bin/3d.exe --batch \"$f\" || exit 1; done")))
6666+ (run ./diff_test.exe)))
52675368; Fuzz tests for schemas (OCaml only - no C dependency)
5469
+48-46
test/diff/fuzz_diff.ml
···44 Stage 1 — compile C roundtrip binary + start subprocess
55 Stage 2 — Crowbar tests: OCaml roundtrip_struct vs C subprocess
6677- The subprocess protocol is itself defined using d3t record codecs:
88- - Request: D3tReq { index : uint32; length : uint32 } ++ data[length]
99- - Response: D3tResp { result : uint32 } ++ data[result] (result < 0 = error)
77+ The subprocess protocol is itself defined using wire record codecs:
88+ - Request: WireReq { index : uint32; length : uint32 } ++ data[length]
99+ - Response: WireResp { result : uint32 } ++ data[result] (result < 0 = error)
10101111- Both sides use d3t-generated read/write functions. *)
1111+ Both sides use wire-generated read/write functions. *)
12121313module Cr = Crowbar
1414module Bs = Bytesrw.Bytes.Slice
15151616(* Helper: encode record to string using slice-based API *)
1717let encode_to_string codec =
1818- let encode = D3t.Staged.unstage (D3t.Record.encode codec) in
1818+ let encode = Wire.Staged.unstage (Wire.Record.encode codec) in
1919 fun v ->
2020 let slice = encode v in
2121 Bytes.sub_string (Bs.bytes slice) (Bs.first slice) (Bs.length slice)
22222323(* Helper: decode record from bytes using slice-based API *)
2424let decode_from_bytes codec =
2525- let decode = D3t.Staged.unstage (D3t.Record.decode codec) in
2525+ let decode = Wire.Staged.unstage (Wire.Record.decode codec) in
2626 fun b ->
2727 if Bytes.length b = 0 then
2828- Error (D3t.Unexpected_eof { expected = 1; got = 0 })
2828+ Error (Wire.Unexpected_eof { expected = 1; got = 0 })
2929 else
3030 let slice = Bs.of_bytes b ~first:0 ~last:(Bytes.length b - 1) in
3131 Ok (decode slice)
32323333-(* ---- One-space protocol (defined with d3t) ---- *)
3333+(* ---- One-space protocol (defined with wire) ---- *)
34343535type request_hdr = { req_index : int32; req_length : int32 }
36363737let request_hdr_codec =
3838- D3t.Record.record "D3tReq"
3838+ Wire.Record.record "WireReq"
3939 ~default:{ req_index = 0l; req_length = 0l }
4040 [
4141- D3t.Record.field "index" D3t.uint32
4141+ Wire.Record.field "index" Wire.uint32
4242 ~get:(fun r -> r.req_index)
4343 ~set:(fun v r -> { r with req_index = v });
4444- D3t.Record.field "length" D3t.uint32
4444+ Wire.Record.field "length" Wire.uint32
4545 ~get:(fun r -> r.req_length)
4646 ~set:(fun v r -> { r with req_length = v });
4747 ]
···4949type response_hdr = { resp_result : int32 }
50505151let response_hdr_codec =
5252- D3t.Record.record "D3tResp" ~default:{ resp_result = 0l }
5252+ Wire.Record.record "WireResp" ~default:{ resp_result = 0l }
5353 [
5454- D3t.Record.field "result" D3t.uint32
5454+ Wire.Record.field "result" Wire.uint32
5555 ~get:(fun r -> r.resp_result)
5656 ~set:(fun v _r -> { resp_result = v });
5757 ]
58585959-let request_hdr_struct = D3t.Record.to_struct request_hdr_codec
6060-let response_hdr_struct = D3t.Record.to_struct response_hdr_codec
5959+let request_hdr_struct = Wire.Record.to_struct request_hdr_codec
6060+let response_hdr_struct = Wire.Record.to_struct response_hdr_codec
61616262(* Stage the protocol encoders/decoders once *)
6363let encode_request_hdr = encode_to_string request_hdr_codec
···6666(* ---- Field type metadata ---- *)
67676868type ft = {
6969- make_field : string -> bool D3t.expr option -> D3t.field;
6969+ make_field : string -> bool Wire.expr option -> Wire.field;
7070 wire_size : int;
7171}
72727373let field_types =
7474 [|
7575 {
7676- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint8);
7676+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint8);
7777 wire_size = 1;
7878 };
7979 {
8080- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint16);
8080+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint16);
8181 wire_size = 2;
8282 };
8383 {
8484- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint16be);
8484+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint16be);
8585 wire_size = 2;
8686 };
8787 {
8888- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint32);
8888+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint32);
8989 wire_size = 4;
9090 };
9191 {
9292- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint32be);
9292+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint32be);
9393 wire_size = 4;
9494 };
9595 {
9696- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint64);
9696+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint64);
9797 wire_size = 8;
9898 };
9999 {
100100- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint64be);
100100+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint64be);
101101 wire_size = 8;
102102 };
103103 |]
104104105105(* ---- Random schema generation ---- *)
106106107107-type random_schema = { struct_ : D3t.struct_; wire_size : int }
107107+type random_schema = { struct_ : Wire.struct_; wire_size : int }
108108109109let gen_constraint_val rng wire_size =
110110 match wire_size with
···127127 let constraint_ =
128128 if Random.State.int rng 4 = 0 then
129129 let k = gen_constraint_val rng ft.wire_size in
130130- Some D3t.Expr.(D3t.ref name <= D3t.int k)
130130+ Some Wire.Expr.(Wire.ref name <= Wire.int k)
131131 else None
132132 in
133133 (ft.make_field name constraint_, ft.wire_size))
134134 in
135135- let d3t_fields = List.map fst fields_data in
135135+ let wire_fields = List.map fst fields_data in
136136 let wire_size = List.fold_left (fun acc (_, ws) -> acc + ws) 0 fields_data in
137137 let struct_name = Fmt.str "Fuzz%d" i in
138138- { struct_ = D3t.struct_ struct_name d3t_fields; wire_size }
138138+ { struct_ = Wire.struct_ struct_name wire_fields; wire_size }
139139140140(* ---- Stage 0: Generate C code ---- *)
141141···147147 p "#include <stdlib.h>";
148148 p "#include <stdint.h>";
149149 p "#include <string.h>";
150150- p "#include \"d3t.h\"";
151151- p "#include \"D3tReq.h\"";
152152- p "#include \"D3tResp.h\"";
150150+ p "#include \"wire.h\"";
151151+ p "#include \"WireReq.h\"";
152152+ p "#include \"WireResp.h\"";
153153 List.iter
154154 (fun rs ->
155155- let name = D3t.struct_name rs.struct_ in
155155+ let name = Wire.struct_name rs.struct_ in
156156 p "#include \"%s.h\"" name)
157157 schemas;
158158 p "";
···162162 p " switch (idx) {";
163163 List.iteri
164164 (fun i rs ->
165165- let name = D3t.struct_name rs.struct_ in
165165+ let name = Wire.struct_name rs.struct_ in
166166 p " case %d: {" i;
167167 p " %s val;" name;
168168 p " int32_t rc = %s_read(buf, len, &val);" name;
···178178 p " uint8_t hdr_buf[8];";
179179 p " for (;;) {";
180180 p " if (fread(hdr_buf, 1, 8, stdin) != 8) break;";
181181- p " D3tReq req;";
182182- p " if (D3tReq_read(hdr_buf, 8, &req) < 0) break;";
181181+ p " WireReq req;";
182182+ p " if (WireReq_read(hdr_buf, 8, &req) < 0) break;";
183183 p " uint8_t *data = malloc(req.length > 0 ? req.length : 1);";
184184 p
185185 " if (req.length > 0 && fread(data, 1, req.length, stdin) != \
···189189 " int32_t result = roundtrip((int)req.index, data, req.length, out, \
190190 sizeof(out));";
191191 p " free(data);";
192192- p " D3tResp resp;";
192192+ p " WireResp resp;";
193193 p " resp.result = (uint32_t)result;";
194194 p " uint8_t resp_buf[4];";
195195- p " D3tResp_write(&resp, resp_buf, 4);";
195195+ p " WireResp_write(&resp, resp_buf, 4);";
196196 p " fwrite(resp_buf, 1, 4, stdout);";
197197 p " if (result > 0) fwrite(out, 1, (size_t)result, stdout);";
198198 p " fflush(stdout);";
···252252 let schemas = List.init num_schemas (fun i -> random_struct rng i) in
253253254254 (* Stage 0: write C code to temp dir *)
255255- let tmpdir = Filename.temp_dir "d3t_fuzz" "" in
255255+ let tmpdir = Filename.temp_dir "wire_fuzz" "" in
256256257257 let write_file path contents =
258258 let oc = open_out path in
259259 output_string oc contents;
260260 close_out oc
261261 in
262262- write_file (Filename.concat tmpdir "d3t.h") (D3t.to_c_runtime ());
262262+ write_file (Filename.concat tmpdir "wire.h") (Wire.to_c_runtime ());
263263264264- (* Protocol headers — generated by d3t *)
265265- D3t.to_c_header_file (Filename.concat tmpdir "D3tReq.h") request_hdr_struct;
266266- D3t.to_c_header_file (Filename.concat tmpdir "D3tResp.h") response_hdr_struct;
264264+ (* Protocol headers — generated by wire *)
265265+ Wire.to_c_header_file (Filename.concat tmpdir "WireReq.h") request_hdr_struct;
266266+ Wire.to_c_header_file
267267+ (Filename.concat tmpdir "WireResp.h")
268268+ response_hdr_struct;
267269268270 List.iter
269271 (fun rs ->
270270- let name = D3t.struct_name rs.struct_ in
272272+ let name = Wire.struct_name rs.struct_ in
271273 write_file
272274 (Filename.concat tmpdir (name ^ ".h"))
273273- (D3t.to_c_header rs.struct_))
275275+ (Wire.to_c_header rs.struct_))
274276 schemas;
275277276278 let c_main = generate_c_main schemas in
···295297 (* Stage 2: register Crowbar tests *)
296298 List.iteri
297299 (fun idx rs ->
298298- let name = D3t.struct_name rs.struct_ in
300300+ let name = Wire.struct_name rs.struct_ in
299301 Cr.add_test ~name:(name ^ " fuzz-diff") [ Cr.bytes ] (fun buf ->
300302 let buf = pad rs.wire_size buf in
301301- let ocaml_result = D3t_diff.Diff.roundtrip_struct rs.struct_ buf in
303303+ let ocaml_result = Wire_diff.Diff.roundtrip_struct rs.struct_ buf in
302304 let c_result = c_roundtrip sub idx buf in
303305 match (ocaml_result, c_result) with
304306 | Ok ocaml_bytes, Some c_bytes ->
···314316 | Error e, Some _ ->
315317 Cr.fail
316318 (Fmt.str "%s: C succeeded but OCaml failed: %a" name
317317- D3t.pp_parse_error e)))
319319+ Wire.pp_parse_error e)))
318320 schemas
+1-1
test/diff/fuzz_schema.ml
···44 When EverParse C integration is available, we can add differential tests. *)
5566module Cr = Crowbar
77-open D3t
77+open Wire
8899let truncate buf =
1010 let max_len = 256 in
+231-22
test/diff/gen_c.ml
···11-(* Generate .3d files from random d3t schemas for EverParse.
11+(* Generate .3d files from random wire schemas for EverParse.
2233 All schemas are randomly generated with deterministic seeds. Fields of any
44 type may get constraints (~25% probability per field). *)
···66(* ---- Field type metadata ---- *)
7788type ft = {
99- make_field : string -> bool D3t.expr option -> D3t.field;
99+ make_field : string -> bool Wire.expr option -> Wire.field;
1010 wire_size : int;
1111 gen_constraint : Random.State.t -> int;
1212+ big_endian : bool;
1213}
13141415let gen_uint8 rng = Random.State.int rng 256
···2324let field_types =
2425 [|
2526 {
2626- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint8);
2727+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint8);
2728 wire_size = 1;
2829 gen_constraint = gen_uint8;
3030+ big_endian = false;
2931 };
3032 {
3131- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint16);
3333+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint16);
3234 wire_size = 2;
3335 gen_constraint = gen_uint16;
3636+ big_endian = false;
3437 };
3538 {
3636- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint16be);
3939+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint16be);
3740 wire_size = 2;
3841 gen_constraint = gen_uint16;
4242+ big_endian = true;
3943 };
4044 {
4141- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint32);
4545+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint32);
4246 wire_size = 4;
4347 gen_constraint = gen_uint32;
4848+ big_endian = false;
4449 };
4550 {
4646- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint32be);
5151+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint32be);
4752 wire_size = 4;
4853 gen_constraint = gen_uint32;
5454+ big_endian = true;
4955 };
5056 {
5151- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint64);
5757+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint64);
5258 wire_size = 8;
5359 gen_constraint = gen_uint64;
6060+ big_endian = false;
5461 };
5562 {
5656- make_field = (fun n c -> D3t.field n ?constraint_:c D3t.uint64be);
6363+ make_field = (fun n c -> Wire.field n ?constraint_:c Wire.uint64be);
5764 wire_size = 8;
5865 gen_constraint = gen_uint64;
6666+ big_endian = true;
5967 };
6068 |]
61696270(* ---- Random schema generation ---- *)
63716464-type random_field = { name : string; ft : ft; constraint_val : int option }
7272+type random_field = {
7373+ name : string;
7474+ ft : ft;
7575+ constraint_val : int option;
7676+ big_endian : bool;
7777+}
65786679type random_schema = {
6767- struct_ : D3t.struct_;
8080+ struct_ : Wire.struct_;
6881 fields : random_field list;
6982 total_wire_size : int;
7083}
···8295 if Random.State.int rng 4 = 0 then Some (ft.gen_constraint rng)
8396 else None
8497 in
8585- { name; ft; constraint_val })
9898+ { name; ft; constraint_val; big_endian = ft.big_endian })
8699 in
87100 let struct_name = Fmt.str "Random%d" seed in
8888- let d3t_fields =
101101+ let wire_fields =
89102 List.map
90103 (fun rf ->
91104 let constraint_ =
92105 Option.map
9393- (fun k -> D3t.Expr.(D3t.ref rf.name <= D3t.int k))
106106+ (fun k -> Wire.Expr.(Wire.ref rf.name <= Wire.int k))
94107 rf.constraint_val
95108 in
96109 rf.ft.make_field rf.name constraint_)
···99112 let total_wire_size =
100113 List.fold_left (fun acc rf -> acc + rf.ft.wire_size) 0 fields
101114 in
102102- { struct_ = D3t.struct_ struct_name d3t_fields; fields; total_wire_size }
115115+ { struct_ = Wire.struct_ struct_name wire_fields; fields; total_wire_size }
116116+117117+(* ---- Code generation for differential testing ---- *)
118118+119119+let generate_c_stubs ~schema_dir outdir schemas =
120120+ let oc = open_out (Filename.concat outdir "stubs.c") in
121121+ let pr fmt = Printf.fprintf oc fmt in
122122+ pr "#include <caml/mlvalues.h>\n";
123123+ pr "#include <caml/memory.h>\n";
124124+ pr "#include <caml/alloc.h>\n";
125125+ pr "#include <stdint.h>\n\n";
126126+ (* Include all wrapper headers - they declare the check functions *)
127127+ List.iter
128128+ (fun rs ->
129129+ let name = Wire.struct_name rs.struct_ in
130130+ pr "#include \"%s/%sWrapper.h\"\n" schema_dir name)
131131+ schemas;
132132+ pr "\n";
133133+ (* Include wrapper implementations with unique error handlers *)
134134+ List.iteri
135135+ (fun i rs ->
136136+ let name = Wire.struct_name rs.struct_ in
137137+ (* Include EverParse.h and parser *)
138138+ if i = 0 then pr "#include \"%s/EverParse.h\"\n" schema_dir;
139139+ pr "#include \"%s/%s.h\"\n" schema_dir name;
140140+ pr "#include \"%s/%s.c\"\n" schema_dir name;
141141+ (* Inline wrapper with renamed error handler *)
142142+ pr
143143+ "void %sEverParseError(const char *s, const char *f, const char *r) { \
144144+ (void)s; (void)f; (void)r; }\n"
145145+ name;
146146+ pr "static void %s_ErrorHandler(\n" name;
147147+ pr " const char *t, const char *f, const char *r,\n";
148148+ pr " uint64_t c, uint8_t *ctx, EVERPARSE_INPUT_BUFFER i, uint64_t p) {\n";
149149+ pr " (void)t; (void)f; (void)r; (void)c; (void)ctx; (void)i; (void)p;\n";
150150+ pr "}\n";
151151+ pr "BOOLEAN %sCheck%s(uint8_t *base, uint32_t len) {\n" name name;
152152+ pr
153153+ " uint64_t result = %sValidate%s(NULL, %s_ErrorHandler, base, len, 0);\n"
154154+ name name name;
155155+ pr " return EverParseIsSuccess(result);\n";
156156+ pr "}\n\n")
157157+ schemas;
158158+ (* Generate OCaml stubs *)
159159+ List.iter
160160+ (fun rs ->
161161+ let name = Wire.struct_name rs.struct_ in
162162+ pr "CAMLprim value caml_%s_check(value v_bytes) {\n"
163163+ (String.lowercase_ascii name);
164164+ pr " CAMLparam1(v_bytes);\n";
165165+ pr " uint8_t *data = (uint8_t *)Bytes_val(v_bytes);\n";
166166+ pr " uint32_t len = caml_string_length(v_bytes);\n";
167167+ pr " BOOLEAN result = %sCheck%s(data, len);\n" name name;
168168+ pr " CAMLreturn(Val_bool(result));\n";
169169+ pr "}\n\n")
170170+ schemas;
171171+ close_out oc
172172+173173+let generate_ml_stubs outdir schemas =
174174+ let oc = open_out (Filename.concat outdir "stubs.ml") in
175175+ let pr fmt = Printf.fprintf oc fmt in
176176+ List.iter
177177+ (fun rs ->
178178+ let name = Wire.struct_name rs.struct_ in
179179+ let lower = String.lowercase_ascii name in
180180+ pr "external %s_check : bytes -> bool = \"caml_%s_check\"\n" lower lower)
181181+ schemas;
182182+ close_out oc
183183+184184+let generate_test_runner outdir schemas =
185185+ let oc = open_out (Filename.concat outdir "diff_test.ml") in
186186+ let pr fmt = Printf.fprintf oc fmt in
187187+ pr "(* Auto-generated differential test runner *)\n\n";
188188+ pr "let num_values = 100\n\n";
189189+ (* Generate schema info: name, wire_size, wire decoder, C checker *)
190190+ pr "type schema = {\n";
191191+ pr " name : string;\n";
192192+ pr " wire_size : int;\n";
193193+ pr " wire_check : bytes -> bool;\n";
194194+ pr " c_check : bytes -> bool;\n";
195195+ pr "}\n\n";
196196+ (* Generate wire validators for each schema using stdlib Bytes *)
197197+ List.iter
198198+ (fun rs ->
199199+ let name = Wire.struct_name rs.struct_ in
200200+ let lower = String.lowercase_ascii name in
201201+ pr "(* %s: wire_size=%d *)\n" name rs.total_wire_size;
202202+ pr "let %s_wire_check (buf : bytes) : bool =\n" lower;
203203+ pr " if Bytes.length buf < %d then false else\n" rs.total_wire_size;
204204+ (* Generate constraint checks with proper offsets *)
205205+ let has_constraints =
206206+ List.exists (fun rf -> rf.constraint_val <> None) rs.fields
207207+ in
208208+ if has_constraints then begin
209209+ (* Calculate offset for each field *)
210210+ let fields_with_offsets =
211211+ let rec aux offset = function
212212+ | [] -> []
213213+ | rf :: rest -> (rf, offset) :: aux (offset + rf.ft.wire_size) rest
214214+ in
215215+ aux 0 rs.fields
216216+ in
217217+ List.iter
218218+ (fun (rf, offset) ->
219219+ match rf.constraint_val with
220220+ | Some k -> (
221221+ let endian = if rf.big_endian then "be" else "le" in
222222+ match rf.ft.wire_size with
223223+ | 1 ->
224224+ pr " let %s = Bytes.get_uint8 buf %d in\n" rf.name offset;
225225+ pr " if %s > %d then false else\n" rf.name k
226226+ | 2 ->
227227+ pr " let %s = Bytes.get_uint16_%s buf %d in\n" rf.name
228228+ endian offset;
229229+ pr " if %s > %d then false else\n" rf.name k
230230+ | 4 ->
231231+ (* Use unsigned comparison for 32-bit values *)
232232+ pr " let %s = Bytes.get_int32_%s buf %d in\n" rf.name
233233+ endian offset;
234234+ pr
235235+ " if Int32.unsigned_compare %s (%ldl) > 0 then false else\n"
236236+ rf.name (Int32.of_int k)
237237+ | 8 ->
238238+ (* Use unsigned comparison for 64-bit values *)
239239+ pr " let %s = Bytes.get_int64_%s buf %d in\n" rf.name
240240+ endian offset;
241241+ pr
242242+ " if Int64.unsigned_compare %s (%LdL) > 0 then false else\n"
243243+ rf.name (Int64.of_int k)
244244+ | _ ->
245245+ pr " let %s = Bytes.get_uint8 buf %d in\n" rf.name offset;
246246+ pr " if %s > %d then false else\n" rf.name k)
247247+ | None -> ())
248248+ fields_with_offsets;
249249+ pr " true\n\n"
250250+ end
251251+ else pr " true\n\n")
252252+ schemas;
253253+ (* Generate schema list *)
254254+ pr "let schemas = [\n";
255255+ List.iter
256256+ (fun rs ->
257257+ let name = Wire.struct_name rs.struct_ in
258258+ let lower = String.lowercase_ascii name in
259259+ pr
260260+ " { name = %S; wire_size = %d; wire_check = %s_wire_check; c_check = \
261261+ Stubs.%s_check };\n"
262262+ name rs.total_wire_size lower lower)
263263+ schemas;
264264+ pr "]\n\n";
265265+ (* Test runner *)
266266+ pr "let () =\n";
267267+ pr " let seed = 42 in\n";
268268+ pr " let rng = Random.State.make [| seed |] in\n";
269269+ pr " let total_tests = ref 0 in\n";
270270+ pr " let mismatches = ref 0 in\n";
271271+ pr " List.iter (fun schema ->\n";
272272+ pr " for _ = 1 to num_values do\n";
273273+ pr " let buf = Bytes.create schema.wire_size in\n";
274274+ pr " for i = 0 to schema.wire_size - 1 do\n";
275275+ pr " Bytes.set buf i (Char.chr (Random.State.int rng 256))\n";
276276+ pr " done;\n";
277277+ pr " let wire_ok = schema.wire_check buf in\n";
278278+ pr " let c_ok = schema.c_check buf in\n";
279279+ pr " incr total_tests;\n";
280280+ pr " if wire_ok <> c_ok then begin\n";
281281+ pr " incr mismatches;\n";
282282+ pr
283283+ " Printf.printf \"MISMATCH %%s: wire=%%b c=%%b\\n\" schema.name \
284284+ wire_ok c_ok\n";
285285+ pr " end\n";
286286+ pr " done\n";
287287+ pr " ) schemas;\n";
288288+ pr
289289+ " Printf.printf \"Tested %%d values across %%d schemas, %%d mismatches\\n\"\n";
290290+ pr " !total_tests (List.length schemas) !mismatches;\n";
291291+ pr " if !mismatches > 0 then exit 1\n";
292292+ close_out oc
293293+294294+let run_everparse schema_dir =
295295+ let cmd =
296296+ Fmt.str
297297+ "cd %s && for f in *.3d; do ~/.local/everparse/bin/3d.exe --batch \"$f\" \
298298+ || exit 1; done"
299299+ schema_dir
300300+ in
301301+ let ret = Sys.command cmd in
302302+ if ret <> 0 then failwith (Fmt.str "EverParse failed with code %d" ret)
103303104304(* ---- Main ---- *)
105305106306let () =
107107- let outdir = if Array.length Sys.argv > 1 then Sys.argv.(1) else "." in
307307+ let schema_dir =
308308+ if Array.length Sys.argv > 1 then Sys.argv.(1) else "schemas"
309309+ in
108310 let num_random =
109311 if Array.length Sys.argv > 2 then int_of_string Sys.argv.(2) else 20
110312 in
111111- (try Unix.mkdir outdir 0o755 with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
313313+ (try Unix.mkdir schema_dir 0o755
314314+ with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
112315 let schemas = List.init num_random (fun i -> random_struct i) in
113113- (* Generate .3d files for EverParse *)
316316+ (* Generate .3d files for EverParse into schema_dir *)
114317 List.iter
115318 (fun rs ->
116116- let name = D3t.struct_name rs.struct_ in
117117- let m = D3t.module_ name [ D3t.typedef ~entrypoint:true rs.struct_ ] in
118118- D3t.to_3d_file (Filename.concat outdir (name ^ ".3d")) m)
119119- schemas
319319+ let name = Wire.struct_name rs.struct_ in
320320+ let m = Wire.module_ name [ Wire.typedef ~entrypoint:true rs.struct_ ] in
321321+ Wire.to_3d_file (Filename.concat schema_dir (name ^ ".3d")) m)
322322+ schemas;
323323+ (* Run EverParse to generate C parsers *)
324324+ run_everparse schema_dir;
325325+ (* Generate FFI stubs and test runner in current dir *)
326326+ generate_c_stubs ~schema_dir "." schemas;
327327+ generate_ml_stubs "." schemas;
328328+ generate_test_runner "." schemas
+2-2
test/diff/gen_schemas.ml
···2233let () =
44 (* Files are generated in the dune build directory *)
55- D3t.to_3d_file "SimpleHeader.3d" Schema.simple_header_module;
66- D3t.to_3d_file "ConstrainedPacket.3d" Schema.constrained_packet_module
55+ Wire.to_3d_file "SimpleHeader.3d" Schema.simple_header_module;
66+ Wire.to_3d_file "ConstrainedPacket.3d" Schema.constrained_packet_module
+1-1
test/diff/schema.ml
···33 These schemas are used to test that our OCaml parser produces the same
44 results as the EverParse-generated C parser. *)
5566-open D3t
66+open Wire
7788(* Simple header schema: version (u8) + length (u16) + flags (u8) *)
99type simple_header = { version : int; length : int; flags : int }
+5-5
test/diff/schema.mli
···33type simple_header = { version : int; length : int; flags : int }
44(** A simple packet header with version, length, and flags fields. *)
5566-val simple_header_codec : simple_header D3t.Codec.t
66+val simple_header_codec : simple_header Wire.Codec.t
77(** Record codec for encoding/decoding simple headers. *)
8899-val simple_header_struct : D3t.struct_
99+val simple_header_struct : Wire.struct_
1010(** Struct definition for 3D code generation. *)
11111212-val simple_header_module : D3t.module_
1212+val simple_header_module : Wire.module_
1313(** Module definition for 3D code generation. *)
14141515type constrained_packet = { pkt_type : int; pkt_length : int }
1616(** A packet with type and length fields, where length must be >= 4. *)
17171818-val constrained_packet_codec : constrained_packet D3t.Codec.t
1818+val constrained_packet_codec : constrained_packet Wire.Codec.t
1919(** Record codec for encoding/decoding constrained packets. *)
20202121-val constrained_packet_module : D3t.module_
2121+val constrained_packet_module : Wire.module_
2222(** Module definition for 3D code generation. *)
+1-1
test/diff/test_diff.ml
···55 decoding random bytes through the OCaml codec. *)
6677module Cr = Crowbar
88-module D = D3t_diff.Diff
88+module D = Wire_diff.Diff
991010let truncate buf =
1111 let max_len = 256 in
+4-7
test/dune
···11(test
22 (name test)
33- (libraries d3t alcotest re))
33+ (libraries wire alcotest re))
4455(executable
66 (name gen_3d)
77- (libraries d3t))
77+ (libraries wire))
8899; EverParse integration tests
1010; First generate .3d files, then run EverParse on them
···2222 (alias 3d)
2323 (deps Bitfields.3d Enumerations.3d FieldDependence.3d)
2424 (action
2525- (progn
2626- (run 3d --version)
2727- (run 3d --batch Bitfields.3d)
2828- (run 3d --batch Enumerations.3d)
2929- (run 3d --batch FieldDependence.3d))))
2525+ (bash
2626+ "~/.local/everparse/bin/3d.exe --version && for f in *.3d; do ~/.local/everparse/bin/3d.exe --batch \"$f\" || exit 1; done")))
30273128; Note: C code generation for differential testing is in the diff/ directory
···11-(* Test d3t library *)
11+(* Test wire library *)
2233-open D3t
33+open Wire
4455let contains ~sub s = Re.execp (Re.compile (Re.str sub)) s
66···116116let test_parse_uint32_le () =
117117 let input = "\x01\x02\x03\x04" in
118118 match parse_string uint32 input with
119119- | Ok v -> Alcotest.(check int32) "uint32 le value" 0x04030201l v
119119+ | Ok v -> Alcotest.(check int) "uint32 le value" 0x04030201 v
120120 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
121121122122let test_parse_uint32_be () =
123123 let input = "\x01\x02\x03\x04" in
124124 match parse_string uint32be input with
125125- | Ok v -> Alcotest.(check int32) "uint32 be value" 0x01020304l v
125125+ | Ok v -> Alcotest.(check int) "uint32 be value" 0x01020304 v
126126 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
127127128128let test_parse_uint64_le () =
···251251 Alcotest.(check string) "uint16 be encoding" "\x01\x02" encoded
252252253253let test_encode_uint32_le () =
254254- let encoded = encode_to_string uint32 0x04030201l in
254254+ let encoded = encode_to_string uint32 0x04030201 in
255255 Alcotest.(check string) "uint32 le encoding" "\x01\x02\x03\x04" encoded
256256257257let test_encode_uint32_be () =
258258- let encoded = encode_to_string uint32be 0x01020304l in
258258+ let encoded = encode_to_string uint32be 0x01020304 in
259259 Alcotest.(check string) "uint32 be encoding" "\x01\x02\x03\x04" encoded
260260261261let test_encode_array () =
···296296 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
297297298298let test_roundtrip_uint32 () =
299299- let original = 0x12345678l in
299299+ let original = 0x12345678 in
300300 let encoded = encode_to_string uint32 original in
301301 match parse_string uint32 encoded with
302302- | Ok decoded -> Alcotest.(check int32) "roundtrip uint32" original decoded
302302+ | Ok decoded -> Alcotest.(check int) "roundtrip uint32" original decoded
303303 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
304304305305let test_roundtrip_array () =
···321321322322(* Record codec tests *)
323323324324-type simple_record = { a : int; b : int; c : int32 }
324324+type simple_record = { a : int; b : int; c : int }
325325326326let simple_record_codec =
327327 let open Codec in
···332332 |> seal
333333334334let test_record_encode () =
335335- let v = { a = 0x42; b = 0x1234; c = 0x56789ABCl } in
335335+ let v = { a = 0x42; b = 0x1234; c = 0x56789ABC } in
336336 match encode_record_to_string simple_record_codec v with
337337 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
338338 | Ok encoded ->
···349349 | Ok v ->
350350 Alcotest.(check int) "a" 0x42 v.a;
351351 Alcotest.(check int) "b" 0x1234 v.b;
352352- Alcotest.(check int32) "c" 0x56789ABCl v.c
352352+ Alcotest.(check int) "c" 0x56789ABC v.c
353353 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e)
354354355355let test_record_roundtrip () =
356356- let original = { a = 0xAB; b = 0xCDEF; c = 0x12345678l } in
356356+ let original = { a = 0xAB; b = 0xCDEF; c = 0x12345678 } in
357357 match encode_record_to_string simple_record_codec original with
358358 | Error e -> Alcotest.fail (Format.asprintf "encode: %a" pp_parse_error e)
359359 | Ok encoded -> (
···361361 | Ok decoded ->
362362 Alcotest.(check int) "a roundtrip" original.a decoded.a;
363363 Alcotest.(check int) "b roundtrip" original.b decoded.b;
364364- Alcotest.(check int32) "c roundtrip" original.c decoded.c
364364+ Alcotest.(check int) "c roundtrip" original.c decoded.c
365365 | Error e -> Alcotest.fail (Format.asprintf "%a" pp_parse_error e))
366366367367let test_record_to_struct () =
···407407 let stubs = to_c_stubs [ s ] in
408408 Alcotest.(check bool)
409409 "contains read stub" true
410410- (contains ~sub:"caml_d3t_SimpleHeader_read" stubs);
410410+ (contains ~sub:"caml_wire_SimpleHeader_read" stubs);
411411 Alcotest.(check bool)
412412 "contains write stub" true
413413- (contains ~sub:"caml_d3t_SimpleHeader_write" stubs)
413413+ (contains ~sub:"caml_wire_SimpleHeader_write" stubs)
414414415415let suite =
416416- ( "d3t",
416416+ ( "wire",
417417 [
418418 (* generation *)
419419 Alcotest.test_case "generation: bitfields" `Quick test_bitfields;
+1-1
test/test_wire.mli
···11val suite : string * unit Alcotest.test_case list
22-(** Alcotest suite for d3t library tests. *)
22+(** Alcotest suite for wire library tests. *)
+34
wire.opam
···11+# This file is generated by dune, edit dune-project instead
22+opam-version: "2.0"
33+synopsis: "Binary wire format DSL with EverParse 3D output"
44+description:
55+ "OCaml DSL for describing binary wire formats with EverParse 3D output. Define your wire format once, then use it for OCaml parsing via bytesrw or emit .3d files for verified C parser generation via EverParse."
66+maintainer: ["Thomas Gazagnaire <thomas@gazagnaire.org>"]
77+authors: ["Thomas Gazagnaire <thomas@gazagnaire.org>"]
88+license: "ISC"
99+homepage: "https://tangled.org/gazagnaire.org/ocaml-wire"
1010+bug-reports: "https://tangled.org/gazagnaire.org/ocaml-wire/issues"
1111+depends: [
1212+ "dune" {>= "3.21"}
1313+ "ocaml" {>= "5.1"}
1414+ "bytesrw" {>= "0.1"}
1515+ "fmt" {>= "0.9"}
1616+ "alcotest" {with-test}
1717+ "odoc" {with-doc}
1818+]
1919+build: [
2020+ ["dune" "subst"] {dev}
2121+ [
2222+ "dune"
2323+ "build"
2424+ "-p"
2525+ name
2626+ "-j"
2727+ jobs
2828+ "@install"
2929+ "@runtest" {with-test}
3030+ "@doc" {with-doc}
3131+ ]
3232+]
3333+dev-repo: "git+https://tangled.org/gazagnaire.org/ocaml-wire"
3434+x-maintenance-intent: ["(latest)"]