Streaming opam file codec for OCaml
0
fork

Configure Feed

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

ocaml-linkedin: apply dune fmt

Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.

+54 -22
+43 -21
README.md
··· 10 10 - `lib/` — value AST, lexer, parser, printer, codec combinators. 11 11 - `lib/bytesrw/` — streaming I/O via [Bytesrw](https://erratique.ch/software/bytesrw). 12 12 13 + ## Installation 14 + 15 + Install with opam: 16 + 17 + ```sh 18 + opam install opam 19 + ``` 20 + 21 + If opam cannot find the package, it may not yet be released in the public 22 + `opam-repository`. Add the overlay repository, then install it: 23 + 24 + ```sh 25 + opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git 26 + opam update 27 + opam install opam 28 + ``` 29 + 13 30 For Eio, combine with [`bytesrw-eio`](../ocaml-bytesrw-eio/): 14 31 15 32 ```ocaml 16 - let r = Bytesrw_eio.bytes_reader_of_flow flow in 17 - Opam_bytesrw.of_reader r 33 + let read_opam_from_flow flow = 34 + let r = Bytesrw_eio.bytes_reader_of_flow flow in 35 + Opam_bytesrw.of_reader r 18 36 ``` 19 37 20 38 For Unix channels, use Bytesrw directly: 21 39 22 40 ```ocaml 23 - let r = Bytesrw.Bytes.Reader.of_in_channel (open_in path) in 24 - Opam_bytesrw.of_reader ~file:path r 41 + let read_opam_from_path path = 42 + let r = Bytesrw.Bytes.Reader.of_in_channel (open_in path) in 43 + Opam_bytesrw.of_reader ~file:path r 25 44 ``` 26 45 27 46 ## Quick start ··· 32 51 type pkg = { name : string; version : string; depends : string list } 33 52 34 53 let pkg_codec : pkg Opam.File.t = 35 - Opam.File.( 54 + Opam.Codec.File.( 36 55 obj (fun name version depends -> { name; version; depends }) 37 - |> field "name" Opam.string ~enc:(fun p -> p.name) 38 - |> field "version" Opam.string ~enc:(fun p -> p.version) 39 - |> field "depends" Opam.(list string) 56 + |> field "name" Opam.Codec.string ~enc:(fun p -> p.name) 57 + |> field "version" Opam.Codec.string ~enc:(fun p -> p.version) 58 + |> field "depends" Opam.Codec.(list string) 40 59 ~dec_absent:[] ~enc:(fun p -> p.depends) 41 60 |> finish) 42 61 43 - let () = 62 + let decode_pkg input = 44 63 match Opam.decode_string pkg_codec input with 45 - | Ok pkg -> ... 46 - | Error e -> prerr_endline (Opam.Error.to_string e) 64 + | Ok pkg -> pkg 65 + | Error e -> failwith (Opam.Error.to_string e) 47 66 ``` 48 67 49 68 For raw value parsing without codecs, use `Opam_bytesrw.of_string` / ··· 55 74 of `Loc.Error.kind`: 56 75 57 76 ```ocaml 58 - match Opam.decode_string pkg_codec s with 59 - | Ok _ -> () 60 - | Error (_, _, Opam.Error.Missing_field name) -> ... 61 - | Error (_, _, Opam.Error.Sort_mismatch { expected; found }) -> ... 62 - | Error e -> prerr_endline (Opam.Error.to_string e) 77 + let report_error codec s = 78 + match Opam.decode_string codec s with 79 + | Ok _ -> () 80 + | Error { kind = Opam.Error.Missing_field _name; _ } -> () 81 + | Error { kind = Opam.Error.Sort_mismatch _; _ } -> () 82 + | Error e -> prerr_endline (Opam.Error.to_string e) 63 83 ``` 64 84 65 85 A printer is registered at module load so `Loc.Error.to_string` ··· 71 91 [`opam-file-format`](https://github.com/ocaml/opam-file-format) on 72 92 real opam files. On typical opam manifests in this monorepo: 73 93 74 - ```text 75 - Geomean full ocaml-opam: 206.1 MB/s (2.30x opam-file-format) 76 - Geomean field ocaml-opam: 333.4 MB/s (3.72x opam-file-format) 77 - Geomean opam-file-format: 89.7 MB/s 94 + <!-- $MDX non-deterministic=command --> 95 + ```sh 96 + $ Geomean full ocaml-opam: 206.1 MB/s (2.30x opam-file-format) 97 + $ Geomean field ocaml-opam: 333.4 MB/s (3.72x opam-file-format) 98 + $ Geomean opam-file-format: 89.7 MB/s 78 99 ``` 79 100 80 101 Two decoding paths: ··· 90 111 91 112 Run with: 92 113 114 + <!-- $MDX non-deterministic=command --> 93 115 ```sh 94 - dune exec ocaml-opam/bench/bench.exe -- ocaml-paseto/paseto.opam ... 116 + $ dune exec ocaml-opam/bench/bench.exe -- ocaml-paseto/paseto.opam ... 95 117 ``` 96 118 97 119 ### How we got there
+4
dune
··· 1 1 (env 2 2 (dev 3 3 (flags :standard %{dune-warnings}))) 4 + 5 + (mdx 6 + (files README.md) 7 + (libraries opam opam.bytesrw bytesrw bytesrw-eio))
+5 -1
dune-project
··· 1 1 (lang dune 3.21) 2 + (using mdx 0.4) 2 3 (name opam) 3 4 4 5 (generate_opam_files true) ··· 23 24 (fmt (>= 0.9.0)) 24 25 (bytesrw (>= 0.1.0)) 25 26 (loc (>= 0.1)) 26 - (alcotest :with-test))) 27 + (mdx :with-test) 28 + (alcotest :with-test) 29 + (bytesrw-eio :with-test)) 30 + )
+2
opam.opam
··· 19 19 "fmt" {>= "0.9.0"} 20 20 "bytesrw" {>= "0.1.0"} 21 21 "loc" {>= "0.1"} 22 + "mdx" {with-test} 22 23 "alcotest" {with-test} 24 + "bytesrw-eio" {with-test} 23 25 "odoc" {with-doc} 24 26 ] 25 27 build: [