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.

feat: Conv.Proj, Conv.Spatial, Conv.Multiscales codecs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+283
+172
src/zarr_jsont.ml
··· 882 882 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (t : Array_meta.t) -> t.unknown) 883 883 |> Jsont.Object.finish 884 884 end 885 + 886 + module Conv = struct 887 + module Meta = struct 888 + type t = { 889 + uuid : string; 890 + name : string; 891 + schema_url : string option; 892 + spec_url : string option; 893 + description : string option; 894 + } 895 + 896 + let uuid t = t.uuid 897 + let name t = t.name 898 + let schema_url t = t.schema_url 899 + let spec_url t = t.spec_url 900 + let description t = t.description 901 + 902 + let jsont = 903 + Jsont.Object.map ~kind:"Conv.Meta" 904 + (fun uuid name schema_url spec_url description -> 905 + { uuid; name; schema_url; spec_url; description }) 906 + |> Jsont.Object.mem "uuid" Jsont.string ~enc:(fun t -> t.uuid) 907 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun t -> t.name) 908 + |> Jsont.Object.opt_mem "schema_url" Jsont.string ~enc:(fun t -> t.schema_url) 909 + |> Jsont.Object.opt_mem "spec_url" Jsont.string ~enc:(fun t -> t.spec_url) 910 + |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun t -> t.description) 911 + |> Jsont.Object.skip_unknown 912 + |> Jsont.Object.finish 913 + end 914 + 915 + module Proj = struct 916 + type t = { 917 + code : string option; 918 + wkt2 : string option; 919 + projjson : Jsont.json option; 920 + } 921 + 922 + let code t = t.code 923 + let wkt2 t = t.wkt2 924 + let projjson t = t.projjson 925 + 926 + let meta = { Meta. 927 + uuid = "f17cb550-5864-4468-aeb7-f3180cfb622f"; 928 + name = "proj:"; 929 + schema_url = Some "https://raw.githubusercontent.com/zarr-experimental/geo-proj/refs/tags/v1/schema.json"; 930 + spec_url = Some "https://github.com/zarr-experimental/geo-proj/blob/v1/README.md"; 931 + description = Some "Coordinate reference system information for geospatial data"; 932 + } 933 + 934 + let jsont = 935 + Jsont.Object.map ~kind:"Conv.Proj" 936 + (fun code wkt2 projjson -> { code; wkt2; projjson }) 937 + |> Jsont.Object.opt_mem "proj:code" Jsont.string ~enc:(fun t -> t.code) 938 + |> Jsont.Object.opt_mem "proj:wkt2" Jsont.string ~enc:(fun t -> t.wkt2) 939 + |> Jsont.Object.opt_mem "proj:projjson" Jsont.json ~enc:(fun t -> t.projjson) 940 + |> Jsont.Object.skip_unknown 941 + |> Jsont.Object.finish 942 + end 943 + 944 + module Spatial = struct 945 + type t = { 946 + dimensions : string list; 947 + bbox : float list option; 948 + transform_type : string option; 949 + transform : float list option; 950 + shape : int list option; 951 + registration : [ `Pixel | `Node ] option; 952 + } 953 + 954 + let dimensions t = t.dimensions 955 + let bbox t = t.bbox 956 + let transform_type t = t.transform_type 957 + let transform t = t.transform 958 + let shape t = t.shape 959 + let registration t = t.registration 960 + 961 + let meta = { Meta. 962 + uuid = "689b58e2-cf7b-45e0-9fff-9cfc0883d6b4"; 963 + name = "spatial:"; 964 + schema_url = Some "https://raw.githubusercontent.com/zarr-conventions/spatial/refs/tags/v1/schema.json"; 965 + spec_url = Some "https://github.com/zarr-conventions/spatial/blob/v1/README.md"; 966 + description = Some "Spatial coordinate information"; 967 + } 968 + 969 + let jsont = 970 + let registration_jsont = Jsont.enum ~kind:"registration" ["pixel", `Pixel; "node", `Node] in 971 + Jsont.Object.map ~kind:"Conv.Spatial" 972 + (fun dimensions bbox transform_type transform shape registration -> 973 + { dimensions; bbox; transform_type; transform; shape; registration }) 974 + |> Jsont.Object.mem "spatial:dimensions" (Jsont.list Jsont.string) ~enc:(fun t -> t.dimensions) 975 + |> Jsont.Object.opt_mem "spatial:bbox" (Jsont.list Jsont.number) ~enc:(fun t -> t.bbox) 976 + |> Jsont.Object.opt_mem "spatial:transform_type" Jsont.string ~enc:(fun t -> t.transform_type) 977 + |> Jsont.Object.opt_mem "spatial:transform" (Jsont.list Jsont.number) ~enc:(fun t -> t.transform) 978 + |> Jsont.Object.opt_mem "spatial:shape" (Jsont.list Jsont.int) ~enc:(fun t -> t.shape) 979 + |> Jsont.Object.opt_mem "spatial:registration" registration_jsont ~enc:(fun t -> t.registration) 980 + |> Jsont.Object.skip_unknown 981 + |> Jsont.Object.finish 982 + end 983 + 984 + module Multiscales = struct 985 + module Transform = struct 986 + type t = { 987 + scale : float list option; 988 + translation : float list option; 989 + unknown : Jsont.json; 990 + } 991 + 992 + let scale t = t.scale 993 + let translation t = t.translation 994 + let unknown t = t.unknown 995 + 996 + let jsont = 997 + Jsont.Object.map ~kind:"Conv.Multiscales.Transform" 998 + (fun scale translation unknown -> { scale; translation; unknown }) 999 + |> Jsont.Object.opt_mem "scale" (Jsont.list Jsont.number) ~enc:(fun t -> t.scale) 1000 + |> Jsont.Object.opt_mem "translation" (Jsont.list Jsont.number) ~enc:(fun t -> t.translation) 1001 + |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown) 1002 + |> Jsont.Object.finish 1003 + end 1004 + 1005 + module Layout_item = struct 1006 + type t = { 1007 + asset : string; 1008 + derived_from : string option; 1009 + transform : Transform.t option; 1010 + resampling_method : string option; 1011 + unknown : Jsont.json; 1012 + } 1013 + 1014 + let asset t = t.asset 1015 + let derived_from t = t.derived_from 1016 + let transform t = t.transform 1017 + let resampling_method t = t.resampling_method 1018 + let unknown t = t.unknown 1019 + 1020 + let jsont = 1021 + Jsont.Object.map ~kind:"Conv.Multiscales.Layout_item" 1022 + (fun asset derived_from transform resampling_method unknown -> 1023 + { asset; derived_from; transform; resampling_method; unknown }) 1024 + |> Jsont.Object.mem "asset" Jsont.string ~enc:(fun t -> t.asset) 1025 + |> Jsont.Object.opt_mem "derived_from" Jsont.string ~enc:(fun t -> t.derived_from) 1026 + |> Jsont.Object.opt_mem "transform" Transform.jsont ~enc:(fun t -> t.transform) 1027 + |> Jsont.Object.opt_mem "resampling_method" Jsont.string ~enc:(fun t -> t.resampling_method) 1028 + |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown) 1029 + |> Jsont.Object.finish 1030 + end 1031 + 1032 + type t = { 1033 + layout : Layout_item.t list; 1034 + resampling_method : string option; 1035 + } 1036 + 1037 + let layout t = t.layout 1038 + let resampling_method t = t.resampling_method 1039 + 1040 + let meta = { Meta. 1041 + uuid = "d35379db-88df-4056-af3a-620245f8e347"; 1042 + name = "multiscales"; 1043 + schema_url = Some "https://raw.githubusercontent.com/zarr-conventions/multiscales/refs/tags/v1/schema.json"; 1044 + spec_url = Some "https://github.com/zarr-conventions/multiscales/blob/v1/README.md"; 1045 + description = Some "Multiscale layout of zarr datasets"; 1046 + } 1047 + 1048 + let jsont = 1049 + Jsont.Object.map ~kind:"Conv.Multiscales" 1050 + (fun layout resampling_method -> { layout; resampling_method }) 1051 + |> Jsont.Object.mem "layout" (Jsont.list Layout_item.jsont) ~enc:(fun t -> t.layout) 1052 + |> Jsont.Object.opt_mem "resampling_method" Jsont.string ~enc:(fun t -> t.resampling_method) 1053 + |> Jsont.Object.skip_unknown 1054 + |> Jsont.Object.finish 1055 + end 1056 + end
+68
src/zarr_jsont.mli
··· 269 269 metadata object. The ["zarr_format"] field is consumed on decode and 270 270 always written as [2] on encode. Unknown fields are preserved. *) 271 271 end 272 + 273 + (** Zarr convention codecs. 274 + 275 + Provides metadata and typed codecs for known Zarr conventions. 276 + Each sub-module exposes a [meta] constant describing the convention 277 + and a [jsont] codec for its attributes. *) 278 + module Conv : sig 279 + (** Convention registration metadata. *) 280 + module Meta : sig 281 + type t 282 + val uuid : t -> string 283 + val name : t -> string 284 + val schema_url : t -> string option 285 + val spec_url : t -> string option 286 + val description : t -> string option 287 + val jsont : t Jsont.t 288 + end 289 + 290 + (** Geo-projection convention attributes ([proj:] prefix). *) 291 + module Proj : sig 292 + type t 293 + val code : t -> string option 294 + val wkt2 : t -> string option 295 + val projjson : t -> Jsont.json option 296 + val meta : Meta.t 297 + val jsont : t Jsont.t 298 + end 299 + 300 + (** Spatial convention attributes ([spatial:] prefix). *) 301 + module Spatial : sig 302 + type t 303 + val dimensions : t -> string list 304 + val bbox : t -> float list option 305 + val transform_type : t -> string option 306 + val transform : t -> float list option 307 + val shape : t -> int list option 308 + val registration : t -> [ `Pixel | `Node ] option 309 + val meta : Meta.t 310 + val jsont : t Jsont.t 311 + end 312 + 313 + (** Multiscales convention attributes. *) 314 + module Multiscales : sig 315 + (** Coordinate transform for a layout item. *) 316 + module Transform : sig 317 + type t 318 + val scale : t -> float list option 319 + val translation : t -> float list option 320 + val unknown : t -> Jsont.json 321 + end 322 + 323 + (** A single entry in the multiscales layout. *) 324 + module Layout_item : sig 325 + type t 326 + val asset : t -> string 327 + val derived_from : t -> string option 328 + val transform : t -> Transform.t option 329 + val resampling_method : t -> string option 330 + val unknown : t -> Jsont.json 331 + end 332 + 333 + type t 334 + val layout : t -> Layout_item.t list 335 + val resampling_method : t -> string option 336 + val meta : Meta.t 337 + val jsont : t Jsont.t 338 + end 339 + end
+43
test/test_zarr_jsont.ml
··· 273 273 | _ -> assert false); 274 274 print_endline "test_v3_array_meta: ok" 275 275 276 + let test_conv_proj () = 277 + let json = {|{"proj:code":"EPSG:4326","other_key":"ignored"}|} in 278 + let v = decode Zarr_jsont.Conv.Proj.jsont json in 279 + assert (Zarr_jsont.Conv.Proj.code v = Some "EPSG:4326"); 280 + assert (Zarr_jsont.Conv.Proj.wkt2 v = None); 281 + assert (Zarr_jsont.Conv.Proj.projjson v = None); 282 + print_endline "test_conv_proj: ok" 283 + 284 + let test_conv_spatial () = 285 + let json = {|{ 286 + "spatial:dimensions": ["Y", "X"], 287 + "spatial:bbox": [-180.0, -90.0, 180.0, 90.0], 288 + "spatial:transform": [1.0, 0.0, 0.0, 0.0, -1.0, 90.0], 289 + "spatial:registration": "pixel" 290 + }|} in 291 + let v = decode Zarr_jsont.Conv.Spatial.jsont json in 292 + assert (Zarr_jsont.Conv.Spatial.dimensions v = ["Y"; "X"]); 293 + assert (Zarr_jsont.Conv.Spatial.registration v = Some `Pixel); 294 + assert (Zarr_jsont.Conv.Spatial.bbox v = Some [-180.0; -90.0; 180.0; 90.0]); 295 + print_endline "test_conv_spatial: ok" 296 + 297 + let test_conv_multiscales () = 298 + let json = {|{ 299 + "layout": [ 300 + {"asset": "0", "transform": {"scale": [1.0, 1.0]}}, 301 + {"asset": "1", "derived_from": "0", "transform": {"scale": [2.0, 2.0]}, "resampling_method": "average"} 302 + ], 303 + "resampling_method": "average" 304 + }|} in 305 + let v = decode Zarr_jsont.Conv.Multiscales.jsont json in 306 + let layout = Zarr_jsont.Conv.Multiscales.layout v in 307 + assert (List.length layout = 2); 308 + let item0 = List.nth layout 0 in 309 + assert (Zarr_jsont.Conv.Multiscales.Layout_item.asset item0 = "0"); 310 + assert (Zarr_jsont.Conv.Multiscales.Layout_item.derived_from item0 = None); 311 + let item1 = List.nth layout 1 in 312 + assert (Zarr_jsont.Conv.Multiscales.Layout_item.derived_from item1 = Some "0"); 313 + assert (Zarr_jsont.Conv.Multiscales.Layout_item.resampling_method item1 = Some "average"); 314 + print_endline "test_conv_multiscales: ok" 315 + 276 316 let () = test_other_codec () 277 317 let () = test_other_ext () 278 318 let () = test_fill_value () ··· 283 323 let () = test_v3_codecs () 284 324 let () = test_v3_data_type () 285 325 let () = test_v3_array_meta () 326 + let () = test_conv_proj () 327 + let () = test_conv_spatial () 328 + let () = test_conv_multiscales ()