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.

refactor: tidy up duplicate helpers, use jdec/jenc consistently, factor patterns

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

+117 -222
+117 -222
src/zarr_jsont.ml
··· 77 77 | _ -> assert false) 78 78 (Jsont.list Jsont.number) 79 79 in 80 + let bool_codec = 81 + Jsont.map ~kind:"fill_value_bool" 82 + ~dec:(fun b -> `Bool b) 83 + ~enc:(function `Bool b -> b | _ -> assert false) 84 + Jsont.bool 85 + in 80 86 Jsont.any ~kind:"fill_value" 81 87 ~dec_null:(Jsont.null `Null) 82 - ~dec_bool:(Jsont.map ~kind:"fill_value_bool" ~dec:(fun b -> `Bool b) ~enc:(function `Bool b -> b | _ -> assert false) Jsont.bool) 88 + ~dec_bool:bool_codec 83 89 ~dec_number:number_codec 84 90 ~dec_string:string_codec 85 91 ~dec_array:array_codec 86 92 ~enc:(function 87 93 | `Null -> Jsont.null `Null 88 - | `Bool _ -> Jsont.map ~kind:"fill_value_bool" ~dec:(fun b -> `Bool b) ~enc:(function `Bool b -> b | _ -> assert false) Jsont.bool 94 + | `Bool _ -> bool_codec 89 95 | `Int _ -> number_codec 90 96 | `Float f when Float.is_nan f || not (Float.is_finite f) -> string_codec 91 97 | `Float _ -> number_codec ··· 321 327 322 328 type codec = Codec.Sharding.codec 323 329 324 - let rec codec_jsont_lazy : codec Jsont.t Lazy.t = lazy ( 325 - let find_name mems = 326 - List.find_map (fun ((name, _), value) -> 327 - if name = "name" then match value with 328 - | Jsont.String (s, _) -> Some s 329 - | _ -> None 330 - else None) mems 330 + (* Shared helpers for name-dispatched object codecs *) 331 + let find_name mems = 332 + List.find_map (fun ((name, _), value) -> 333 + if name = "name" then match value with 334 + | Jsont.String (s, _) -> Some s 335 + | _ -> None 336 + else None) mems 337 + 338 + let find_config mems = 339 + List.find_map (fun ((name, _), value) -> 340 + if name = "configuration" then Some value else None) mems 341 + 342 + let decode_config codec_t config_json = jdec codec_t config_json 343 + 344 + let encode_named name config_json = 345 + let mems = [ (("name", Jsont.Meta.none), Jsont.Json.string name) ] in 346 + let mems = match config_json with 347 + | None -> mems 348 + | Some c -> mems @ [ (("configuration", Jsont.Meta.none), c) ] 331 349 in 332 - let find_config mems = 333 - List.find_map (fun ((name, _), value) -> 334 - if name = "configuration" then Some value else None) mems 335 - in 336 - let decode_config codec_t config_json = 337 - match Jsont.Json.decode codec_t config_json with 338 - | Ok v -> v | Error e -> invalid_arg e 339 - in 340 - let encode_named name config_json = 341 - let mems = [ (("name", Jsont.Meta.none), Jsont.Json.string name) ] in 342 - let mems = match config_json with 343 - | None -> mems 344 - | Some c -> mems @ [ (("configuration", Jsont.Meta.none), c) ] 350 + Jsont.Json.object' mems 351 + 352 + let encode_config codec_t v = jenc codec_t v 353 + 354 + let decode_other_ext json = jdec Other_ext.jsont json 355 + 356 + let encode_other_ext o = jenc Other_ext.jsont o 357 + 358 + let name_dispatch ~kind cases json = 359 + match json with 360 + | Jsont.Object (mems, _) -> 361 + let name = match find_name mems with 362 + | Some n -> n | None -> Jsont.Error.msgf Jsont.Meta.none "%s: missing name" kind 363 + in 364 + let config = match find_config mems with 365 + | Some c -> c | None -> Jsont.Json.object' [] 345 366 in 346 - Jsont.Json.object' mems 347 - in 348 - let encode_config codec_t v = 349 - match Jsont.Json.encode codec_t v with 350 - | Ok j -> j | Error e -> invalid_arg e 351 - in 367 + (match List.assoc_opt name cases with 368 + | Some codec -> jdec codec config 369 + | None -> `Other (jdec Other_ext.jsont json)) 370 + | _ -> Jsont.Error.msgf Jsont.Meta.none "%s: expected object" kind 371 + 372 + let rec codec_jsont_lazy : codec Jsont.t Lazy.t = lazy ( 352 373 let index_location_jsont = 353 374 Jsont.enum ~kind:"index_location" ["start", `Start; "end", `End] 354 375 in ··· 378 399 | Jsont.Object (mems, _) -> 379 400 let name = match find_name mems with 380 401 | Some n -> n 381 - | None -> invalid_arg "codec: missing name" 402 + | None -> Jsont.Error.msgf Jsont.Meta.none "codec: missing name" 382 403 in 383 404 let config = find_config mems in 384 405 let config_or_empty = match config with ··· 396 417 `Transpose (decode_config Codec.Transpose.jsont config_or_empty) 397 418 | "sharding_indexed" -> 398 419 `Sharding (decode_config sharding_config_jsont config_or_empty) 399 - | _ -> 400 - (match Jsont.Json.decode Other_ext.jsont json with 401 - | Ok o -> `Other o 402 - | Error e -> invalid_arg e)) 403 - | _ -> invalid_arg "codec: expected object") 420 + | _ -> `Other (decode_other_ext json)) 421 + | _ -> Jsont.Error.msgf Jsont.Meta.none "codec: expected object") 404 422 ~enc:(function 405 423 | `Bytes b -> 406 424 encode_named "bytes" (Some (encode_config Codec.Bytes.jsont b)) ··· 414 432 encode_named "transpose" (Some (encode_config Codec.Transpose.jsont t)) 415 433 | `Sharding s -> 416 434 encode_named "sharding_indexed" (Some (encode_config sharding_config_jsont s)) 417 - | `Other o -> 418 - (match Jsont.Json.encode Other_ext.jsont o with 419 - | Ok j -> j | Error e -> invalid_arg e)) 435 + | `Other o -> encode_other_ext o) 420 436 Jsont.json 421 437 ) 422 438 423 439 let codec_jsont : codec Jsont.t = Jsont.rec' codec_jsont_lazy 424 - 425 - (* Shared helpers for name-dispatched object codecs *) 426 - let find_name mems = 427 - List.find_map (fun ((name, _), value) -> 428 - if name = "name" then match value with 429 - | Jsont.String (s, _) -> Some s 430 - | _ -> None 431 - else None) mems 432 - 433 - let find_config mems = 434 - List.find_map (fun ((name, _), value) -> 435 - if name = "configuration" then Some value else None) mems 436 - 437 - let decode_config codec_t config_json = 438 - match Jsont.Json.decode codec_t config_json with 439 - | Ok v -> v | Error e -> invalid_arg e 440 - 441 - let encode_named name config_json = 442 - let mems = [ (("name", Jsont.Meta.none), Jsont.Json.string name) ] in 443 - let mems = match config_json with 444 - | None -> mems 445 - | Some c -> mems @ [ (("configuration", Jsont.Meta.none), c) ] 446 - in 447 - Jsont.Json.object' mems 448 - 449 - let encode_config codec_t v = 450 - match Jsont.Json.encode codec_t v with 451 - | Ok j -> j | Error e -> invalid_arg e 452 - 453 - let decode_other_ext json = 454 - match Jsont.Json.decode Other_ext.jsont json with 455 - | Ok o -> o | Error e -> invalid_arg e 456 - 457 - let encode_other_ext o = 458 - match Jsont.Json.encode Other_ext.jsont o with 459 - | Ok j -> j | Error e -> invalid_arg e 460 440 461 441 module Data_type = struct 462 442 type t = [ ··· 514 494 if String.length s >= 2 && s.[0] = 'r' then 515 495 let bits_str = String.sub s 1 (String.length s - 1) in 516 496 (try `Raw (int_of_string bits_str) 517 - with _ -> invalid_arg (Printf.sprintf "V3.Data_type: unknown type %s" s)) 497 + with _ -> Jsont.Error.msgf Jsont.Meta.none "V3.Data_type: unknown type %s" s) 518 498 else 519 - invalid_arg (Printf.sprintf "V3.Data_type: unknown type %s" s)) 499 + Jsont.Error.msgf Jsont.Meta.none "V3.Data_type: unknown type %s" s) 520 500 ~enc:enc_string 521 501 Jsont.string 522 502 in ··· 533 513 ~dec_object 534 514 ~enc:(function 535 515 | `Other _ -> dec_object 536 - | v -> ignore v; dec_string) 516 + | _ -> dec_string) 537 517 () 538 518 539 519 module Chunk_grid = struct ··· 551 531 end 552 532 553 533 let chunk_grid_jsont : Chunk_grid.t Jsont.t = 534 + let regular_codec = Jsont.map ~kind:"regular_grid" 535 + ~dec:(fun r -> `Regular r) 536 + ~enc:(function `Regular r -> r | _ -> assert false) 537 + Chunk_grid.Regular.jsont 538 + in 554 539 Jsont.map ~kind:"V3.Chunk_grid" 555 - ~dec:(fun json -> 556 - match json with 557 - | Jsont.Object (mems, _) -> 558 - let name = match find_name mems with 559 - | Some n -> n 560 - | None -> invalid_arg "chunk_grid: missing name" 561 - in 562 - let config = find_config mems in 563 - (match name with 564 - | "regular" -> 565 - let config = match config with 566 - | Some c -> c 567 - | None -> invalid_arg "chunk_grid regular: missing configuration" 568 - in 569 - `Regular (decode_config Chunk_grid.Regular.jsont config) 570 - | _ -> `Other (decode_other_ext json)) 571 - | _ -> invalid_arg "chunk_grid: expected object") 540 + ~dec:(fun json -> name_dispatch ~kind:"chunk_grid" ["regular", regular_codec] json) 572 541 ~enc:(function 573 542 | `Regular r -> 574 543 encode_named "regular" (Some (encode_config Chunk_grid.Regular.jsont r)) ··· 592 561 end 593 562 594 563 let chunk_key_encoding_jsont : Chunk_key_encoding.t Jsont.t = 564 + let default_codec = Jsont.map ~kind:"default_encoding" 565 + ~dec:(fun d -> `Default d) 566 + ~enc:(function `Default d -> d | _ -> assert false) 567 + Chunk_key_encoding.Default.jsont 568 + in 595 569 Jsont.map ~kind:"V3.Chunk_key_encoding" 596 - ~dec:(fun json -> 597 - match json with 598 - | Jsont.Object (mems, _) -> 599 - let name = match find_name mems with 600 - | Some n -> n 601 - | None -> invalid_arg "chunk_key_encoding: missing name" 602 - in 603 - let config = find_config mems in 604 - (match name with 605 - | "default" -> 606 - let config = match config with 607 - | Some c -> c 608 - | None -> Jsont.Json.object' [] 609 - in 610 - `Default (decode_config Chunk_key_encoding.Default.jsont config) 611 - | _ -> `Other (decode_other_ext json)) 612 - | _ -> invalid_arg "chunk_key_encoding: expected object") 570 + ~dec:(fun json -> name_dispatch ~kind:"chunk_key_encoding" ["default", default_codec] json) 613 571 ~enc:(function 614 572 | `Default d -> 615 573 encode_named "default" (Some (encode_config Chunk_key_encoding.Default.jsont d)) ··· 745 703 | Jsont.Object (mems, _meta) -> 746 704 let id = find_id mems in 747 705 (match id with 748 - | Some "blosc" -> 749 - (match Jsont.Json.decode Compressor.Blosc.jsont json with 750 - | Ok b -> `Blosc b 751 - | Error e -> invalid_arg e) 752 - | Some "zlib" -> 753 - (match Jsont.Json.decode Compressor.Zlib.jsont json with 754 - | Ok z -> `Zlib z 755 - | Error e -> invalid_arg e) 756 - | _ -> 757 - (match Jsont.Json.decode Other_codec.jsont json with 758 - | Ok o -> `Other o 759 - | Error e -> invalid_arg e)) 760 - | _ -> invalid_arg "V2.Compressor: expected object") 706 + | Some "blosc" -> `Blosc (jdec Compressor.Blosc.jsont json) 707 + | Some "zlib" -> `Zlib (jdec Compressor.Zlib.jsont json) 708 + | _ -> `Other (jdec Other_codec.jsont json)) 709 + | _ -> Jsont.Error.msgf Jsont.Meta.none "V2.Compressor: expected object") 761 710 ~enc:(function 762 - | `Blosc b -> 763 - (match Jsont.Json.encode Compressor.Blosc.jsont b with 764 - | Ok j -> j | Error e -> invalid_arg e) 765 - | `Zlib z -> 766 - (match Jsont.Json.encode Compressor.Zlib.jsont z with 767 - | Ok j -> j | Error e -> invalid_arg e) 768 - | `Other o -> 769 - (match Jsont.Json.encode Other_codec.jsont o with 770 - | Ok j -> j | Error e -> invalid_arg e)) 711 + | `Blosc b -> jenc Compressor.Blosc.jsont b 712 + | `Zlib z -> jenc Compressor.Zlib.jsont z 713 + | `Other o -> jenc Other_codec.jsont o) 771 714 Jsont.json 772 715 773 716 module Filter = struct ··· 805 748 | Jsont.Object (mems, _meta) -> 806 749 let id = find_id mems in 807 750 (match id with 808 - | Some "delta" -> 809 - (match Jsont.Json.decode Filter.Delta.jsont json with 810 - | Ok d -> `Delta d 811 - | Error e -> invalid_arg e) 812 - | _ -> 813 - (match Jsont.Json.decode Other_codec.jsont json with 814 - | Ok o -> `Other o 815 - | Error e -> invalid_arg e)) 816 - | _ -> invalid_arg "V2.Filter: expected object") 751 + | Some "delta" -> `Delta (jdec Filter.Delta.jsont json) 752 + | _ -> `Other (jdec Other_codec.jsont json)) 753 + | _ -> Jsont.Error.msgf Jsont.Meta.none "V2.Filter: expected object") 817 754 ~enc:(function 818 - | `Delta d -> 819 - (match Jsont.Json.encode Filter.Delta.jsont d with 820 - | Ok j -> j | Error e -> invalid_arg e) 821 - | `Other o -> 822 - (match Jsont.Json.encode Other_codec.jsont o with 823 - | Ok j -> j | Error e -> invalid_arg e)) 755 + | `Delta d -> jenc Filter.Delta.jsont d 756 + | `Other o -> jenc Other_codec.jsont o) 824 757 Jsont.json 825 758 826 759 module Array_meta = struct ··· 1025 958 let nodata t = t.nodata 1026 959 let nodata_jsont = 1027 960 let from_string = Jsont.map ~kind:"nodata" 1028 - ~dec:(fun s -> s) ~enc:(fun s -> s) Jsont.string in 961 + ~dec:Fun.id ~enc:Fun.id Jsont.string in 1029 962 let from_number = Jsont.map ~kind:"nodata" 1030 963 ~dec:(fun f -> Printf.sprintf "%g" f) 1031 964 ~enc:(fun _ -> 0.0) ··· 1250 1183 } 1251 1184 end 1252 1185 1186 + let emit_prefixed prefix conv_jsont value add = 1187 + match value with 1188 + | None -> () 1189 + | Some v -> 1190 + match Jsont.Json.encode conv_jsont v with 1191 + | Ok (Jsont.Object (ms, _)) -> 1192 + List.iter (fun ((k, _), _ as m) -> 1193 + if String.length k > String.length prefix 1194 + && String.sub k 0 (String.length prefix) = prefix 1195 + then add m) ms 1196 + | _ -> () 1197 + 1253 1198 let attrs_jsont : Attrs.t Jsont.t = 1254 1199 Jsont.map ~kind:"Attrs" 1255 1200 ~dec:(fun json -> ··· 1335 1280 | Ok arr -> add (("zarr_conventions", Jsont.Meta.none), arr) 1336 1281 | Error _ -> () 1337 1282 end; 1338 - (* proj *) 1339 - (match t.proj with 1340 - | Some p -> 1341 - (match Jsont.Json.encode Conv.Proj.jsont p with 1342 - | Ok (Jsont.Object (proj_mems, _)) -> 1343 - List.iter (fun ((k, _), _ as m) -> 1344 - if String.length k > 5 && String.sub k 0 5 = "proj:" then add m 1345 - ) proj_mems 1346 - | _ -> ()) 1347 - | None -> ()); 1348 - (* spatial *) 1349 - (match t.spatial with 1350 - | Some s -> 1351 - (match Jsont.Json.encode Conv.Spatial.jsont s with 1352 - | Ok (Jsont.Object (sp_mems, _)) -> 1353 - List.iter (fun ((k, _), _ as m) -> 1354 - if String.length k > 8 && String.sub k 0 8 = "spatial:" then add m 1355 - ) sp_mems 1356 - | _ -> ()) 1357 - | None -> ()); 1283 + emit_prefixed "proj:" Conv.Proj.jsont t.proj add; 1284 + emit_prefixed "spatial:" Conv.Spatial.jsont t.spatial add; 1358 1285 (* multiscales *) 1359 1286 (match t.multiscales with 1360 1287 | Some m -> ··· 1362 1289 | Ok j -> add (("multiscales", Jsont.Meta.none), j) 1363 1290 | _ -> ()) 1364 1291 | None -> ()); 1365 - (* geoemb *) 1366 - (match t.geoemb with 1367 - | Some g -> 1368 - (match Jsont.Json.encode Conv.Geoemb.jsont g with 1369 - | Ok (Jsont.Object (gm, _)) -> 1370 - List.iter (fun ((k, _), _ as m) -> 1371 - if String.length k > 7 && String.sub k 0 7 = "geoemb:" then add m 1372 - ) gm 1373 - | _ -> ()) 1374 - | None -> ()); 1292 + emit_prefixed "geoemb:" Conv.Geoemb.jsont t.geoemb add; 1375 1293 (* unknown *) 1376 1294 (match t.unknown with 1377 1295 | Jsont.Object (unk_mems, _) -> List.iter add unk_mems ··· 1412 1330 ~enc:(fun t -> 1413 1331 match t.V2_node.kind with 1414 1332 | `Array a -> a 1415 - | `Group -> invalid_arg "v2_array_jsont: not an array") 1333 + | `Group -> Jsont.Error.msgf Jsont.Meta.none "v2_array_jsont: not an array") 1416 1334 V2.array_meta_jsont 1417 1335 1418 1336 let v2_group_jsont : V2_node.t Jsont.t = ··· 1437 1355 ~dec:(fun json -> 1438 1356 let mems = match json with 1439 1357 | Jsont.Object (m, _) -> m 1440 - | _ -> invalid_arg "v3_jsont: expected object" 1358 + | _ -> Jsont.Error.msgf Jsont.Meta.none "v3_jsont: expected object" 1441 1359 in 1442 1360 let node_type = match find_mem mems "node_type" with 1443 1361 | Some (Jsont.String (s, _)) -> s 1444 - | _ -> invalid_arg "v3_jsont: missing node_type" 1362 + | _ -> Jsont.Error.msgf Jsont.Meta.none "v3_jsont: missing node_type" 1445 1363 in 1446 1364 let attrs_val = 1447 1365 match find_mem mems "attributes" with ··· 1463 1381 let unknown_val = Jsont.Json.object' unknown_mems in 1464 1382 (match node_type with 1465 1383 | "array" -> 1466 - let arr = match Jsont.Json.decode V3.array_meta_jsont json with 1467 - | Ok a -> a 1468 - | Error e -> invalid_arg ("v3_jsont: " ^ e) 1469 - in 1384 + let arr = jdec V3.array_meta_jsont json in 1470 1385 V3_node.{ kind = `Array arr; attrs = attrs_val; unknown = unknown_val } 1471 1386 | "group" -> 1472 1387 V3_node.{ kind = `Group; attrs = attrs_val; unknown = unknown_val } 1473 - | s -> invalid_arg ("v3_jsont: unknown node_type: " ^ s))) 1388 + | s -> Jsont.Error.msgf Jsont.Meta.none "v3_jsont: unknown node_type: %s" s)) 1474 1389 ~enc:(fun (t : V3_node.t) -> 1475 - let attrs_json = 1476 - match Jsont.Json.encode attrs_jsont t.attrs with 1477 - | Ok j -> j 1478 - | Error e -> invalid_arg ("v3_jsont enc attrs: " ^ e) 1479 - in 1390 + let attrs_json = jenc attrs_jsont t.attrs in 1480 1391 let has_attrs = match attrs_json with 1481 1392 | Jsont.Object ([], _) -> false 1482 1393 | _ -> true 1483 1394 in 1484 1395 match t.kind with 1485 1396 | `Array a -> 1486 - let arr_json = match Jsont.Json.encode V3.array_meta_jsont a with 1487 - | Ok j -> j 1488 - | Error e -> invalid_arg ("v3_jsont enc array: " ^ e) 1489 - in 1397 + let arr_json = jenc V3.array_meta_jsont a in 1490 1398 let arr_mems = match arr_json with 1491 1399 | Jsont.Object (m, _) -> m 1492 1400 | _ -> [] ··· 1526 1434 ~dec:(fun json -> 1527 1435 let mems = match json with 1528 1436 | Jsont.Object (m, _) -> m 1529 - | _ -> invalid_arg "jsont: expected object" 1437 + | _ -> Jsont.Error.msgf Jsont.Meta.none "jsont: expected object" 1530 1438 in 1531 1439 let zarr_format = match find_zarr_format mems with 1532 1440 | Some n -> n 1533 - | None -> invalid_arg "jsont: missing zarr_format" 1441 + | None -> Jsont.Error.msgf Jsont.Meta.none "jsont: missing zarr_format" 1534 1442 in 1535 1443 match zarr_format with 1536 1444 | 2 -> 1537 - if has_shape mems then 1538 - match Jsont.Json.decode v2_array_jsont json with 1539 - | Ok n -> `V2 n | Error e -> invalid_arg e 1540 - else 1541 - (match Jsont.Json.decode v2_group_jsont json with 1542 - | Ok n -> `V2 n | Error e -> invalid_arg e) 1543 - | 3 -> 1544 - (match Jsont.Json.decode v3_jsont json with 1545 - | Ok n -> `V3 n | Error e -> invalid_arg e) 1546 - | n -> invalid_arg (Printf.sprintf "jsont: unknown zarr_format: %d" n)) 1445 + if has_shape mems then `V2 (jdec v2_array_jsont json) 1446 + else `V2 (jdec v2_group_jsont json) 1447 + | 3 -> `V3 (jdec v3_jsont json) 1448 + | n -> Jsont.Error.msgf Jsont.Meta.none "jsont: unknown zarr_format: %d" n) 1547 1449 ~enc:(function 1548 1450 | `V2 node -> 1549 1451 (match V2_node.kind node with 1550 - | `Array _ -> 1551 - (match Jsont.Json.encode v2_array_jsont node with 1552 - | Ok j -> j | Error e -> invalid_arg e) 1553 - | `Group -> 1554 - (match Jsont.Json.encode v2_group_jsont node with 1555 - | Ok j -> j | Error e -> invalid_arg e)) 1556 - | `V3 node -> 1557 - (match Jsont.Json.encode v3_jsont node with 1558 - | Ok j -> j | Error e -> invalid_arg e)) 1452 + | `Array _ -> jenc v2_array_jsont node 1453 + | `Group -> jenc v2_group_jsont node) 1454 + | `V3 node -> jenc v3_jsont node) 1559 1455 Jsont.json 1560 1456 1561 1457 (* Consolidated metadata — V3 *) ··· 1573 1469 Jsont.map ~kind:"Consolidated" 1574 1470 ~dec:(fun json -> 1575 1471 let mems = match json with 1576 - | Jsont.Object (mems, _) -> mems | _ -> invalid_arg "expected object" 1472 + | Jsont.Object (mems, _) -> mems 1473 + | _ -> Jsont.Error.msgf Jsont.Meta.none "Consolidated: expected object" 1577 1474 in 1578 1475 let find k = List.find_map (fun ((n, _), v) -> 1579 1476 if n = k then Some v else None) mems ··· 1592 1489 { metadata; kind }) 1593 1490 ~enc:(fun t -> 1594 1491 let entries = List.map (fun (path, node) -> 1595 - let node_json = match Jsont.Json.encode v3_jsont node with 1596 - | Ok j -> j | Error e -> invalid_arg e 1597 - in 1598 - ((path, Jsont.Meta.none), node_json)) t.metadata 1492 + ((path, Jsont.Meta.none), jenc v3_jsont node)) t.metadata 1599 1493 in 1600 1494 Jsont.Json.object' [ 1601 1495 (("metadata", Jsont.Meta.none), Jsont.Object (entries, Jsont.Meta.none)); ··· 1626 1520 Jsont.map ~kind:"V2_consolidated" 1627 1521 ~dec:(fun json -> 1628 1522 let mems = match json with 1629 - | Jsont.Object (mems, _) -> mems | _ -> invalid_arg "expected object" 1523 + | Jsont.Object (mems, _) -> mems 1524 + | _ -> Jsont.Error.msgf Jsont.Meta.none "V2_consolidated: expected object" 1630 1525 in 1631 1526 let find k = List.find_map (fun ((n, _), v) -> 1632 1527 if n = k then Some v else None) mems