OCaml Zarr jsont codecs for v2/v3 and common conventions
0
fork

Configure Feed

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

fix: handle missing codec configuration gracefully

Pass empty object to sub-codecs when configuration is absent, letting
the codec's own field declarations (mem vs opt_mem with dec_absent)
determine what's required. This produces proper jsont errors for
genuinely missing required fields.

Make Codec.Bytes.endian optional (None for single-byte data types).

Tested against geotessera.org zarr store (464 nodes, some bytes codecs
without configuration).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+23 -11
+20 -9
src/zarr_jsont.ml
··· 272 272 module V3 = struct 273 273 module Codec = struct 274 274 module Bytes = struct 275 - type t = { endian : [ `Little | `Big ] } 275 + type t = { endian : [ `Little | `Big ] option } 276 276 let endian t = t.endian 277 277 let endian_jsont = Jsont.enum ~kind:"endian" ["little", `Little; "big", `Big] 278 278 let jsont = 279 279 Jsont.Object.map ~kind:"Bytes.config" (fun e -> { endian = e }) 280 - |> Jsont.Object.mem "endian" endian_jsont ~enc:(fun t -> t.endian) 280 + |> Jsont.Object.opt_mem "endian" endian_jsont ~enc:(fun t -> t.endian) 281 281 |> Jsont.Object.skip_unknown 282 282 |> Jsont.Object.finish 283 283 end ··· 414 414 | None -> invalid_arg "codec: missing name" 415 415 in 416 416 let config = find_config mems in 417 + let config_or_empty = match config with 418 + | Some c -> c | None -> Jsont.Json.object' [] 419 + in 417 420 (match name with 418 421 | "bytes" -> 419 - `Bytes (decode_config Codec.Bytes.jsont (Option.get config)) 422 + `Bytes (decode_config Codec.Bytes.jsont config_or_empty) 420 423 | "gzip" -> 421 - `Gzip (decode_config Codec.Gzip.jsont (Option.get config)) 424 + `Gzip (decode_config Codec.Gzip.jsont config_or_empty) 422 425 | "blosc" -> 423 - `Blosc (decode_config Codec.Blosc.jsont (Option.get config)) 426 + `Blosc (decode_config Codec.Blosc.jsont config_or_empty) 424 427 | "crc32c" -> `Crc32c 425 428 | "transpose" -> 426 - `Transpose (decode_config Codec.Transpose.jsont (Option.get config)) 429 + `Transpose (decode_config Codec.Transpose.jsont config_or_empty) 427 430 | "sharding_indexed" -> 428 - `Sharding (decode_config sharding_config_jsont (Option.get config)) 431 + `Sharding (decode_config sharding_config_jsont config_or_empty) 429 432 | _ -> 430 433 (match Jsont.Json.decode Other_ext.jsont json with 431 434 | Ok o -> `Other o ··· 592 595 let config = find_config mems in 593 596 (match name with 594 597 | "regular" -> 595 - `Regular (decode_config Chunk_grid.Regular.jsont (Option.get config)) 598 + let config = match config with 599 + | Some c -> c 600 + | None -> invalid_arg "chunk_grid regular: missing configuration" 601 + in 602 + `Regular (decode_config Chunk_grid.Regular.jsont config) 596 603 | _ -> `Other (decode_other_ext json)) 597 604 | _ -> invalid_arg "chunk_grid: expected object") 598 605 ~enc:(function ··· 629 636 let config = find_config mems in 630 637 (match name with 631 638 | "default" -> 632 - `Default (decode_config Chunk_key_encoding.Default.jsont (Option.get config)) 639 + let config = match config with 640 + | Some c -> c 641 + | None -> Jsont.Json.object' [] 642 + in 643 + `Default (decode_config Chunk_key_encoding.Default.jsont config) 633 644 | _ -> `Other (decode_other_ext json)) 634 645 | _ -> invalid_arg "chunk_key_encoding: expected object") 635 646 ~enc:(function
+2 -1
src/zarr_jsont.mli
··· 78 78 (** Bytes codec configuration. *) 79 79 module Bytes : sig 80 80 type t 81 - val endian : t -> [ `Little | `Big ] 81 + val endian : t -> [ `Little | `Big ] option 82 + (** [None] when endian is not applicable (single-byte data types). *) 82 83 end 83 84 84 85 (** Gzip codec configuration. *)
+1 -1
test/test_zarr_jsont.ml
··· 203 203 (* bytes *) 204 204 let v = decode c {|{"name":"bytes","configuration":{"endian":"little"}}|} in 205 205 (match v with 206 - | `Bytes b -> assert (Zarr_jsont.V3.Codec.Bytes.endian b = `Little) 206 + | `Bytes b -> assert (Zarr_jsont.V3.Codec.Bytes.endian b = Some `Little) 207 207 | _ -> assert false); 208 208 (* gzip *) 209 209 let v = decode c {|{"name":"gzip","configuration":{"level":5}}|} in