···882882 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (t : Array_meta.t) -> t.unknown)
883883 |> Jsont.Object.finish
884884end
885885+886886+module Conv = struct
887887+ module Meta = struct
888888+ type t = {
889889+ uuid : string;
890890+ name : string;
891891+ schema_url : string option;
892892+ spec_url : string option;
893893+ description : string option;
894894+ }
895895+896896+ let uuid t = t.uuid
897897+ let name t = t.name
898898+ let schema_url t = t.schema_url
899899+ let spec_url t = t.spec_url
900900+ let description t = t.description
901901+902902+ let jsont =
903903+ Jsont.Object.map ~kind:"Conv.Meta"
904904+ (fun uuid name schema_url spec_url description ->
905905+ { uuid; name; schema_url; spec_url; description })
906906+ |> Jsont.Object.mem "uuid" Jsont.string ~enc:(fun t -> t.uuid)
907907+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun t -> t.name)
908908+ |> Jsont.Object.opt_mem "schema_url" Jsont.string ~enc:(fun t -> t.schema_url)
909909+ |> Jsont.Object.opt_mem "spec_url" Jsont.string ~enc:(fun t -> t.spec_url)
910910+ |> Jsont.Object.opt_mem "description" Jsont.string ~enc:(fun t -> t.description)
911911+ |> Jsont.Object.skip_unknown
912912+ |> Jsont.Object.finish
913913+ end
914914+915915+ module Proj = struct
916916+ type t = {
917917+ code : string option;
918918+ wkt2 : string option;
919919+ projjson : Jsont.json option;
920920+ }
921921+922922+ let code t = t.code
923923+ let wkt2 t = t.wkt2
924924+ let projjson t = t.projjson
925925+926926+ let meta = { Meta.
927927+ uuid = "f17cb550-5864-4468-aeb7-f3180cfb622f";
928928+ name = "proj:";
929929+ schema_url = Some "https://raw.githubusercontent.com/zarr-experimental/geo-proj/refs/tags/v1/schema.json";
930930+ spec_url = Some "https://github.com/zarr-experimental/geo-proj/blob/v1/README.md";
931931+ description = Some "Coordinate reference system information for geospatial data";
932932+ }
933933+934934+ let jsont =
935935+ Jsont.Object.map ~kind:"Conv.Proj"
936936+ (fun code wkt2 projjson -> { code; wkt2; projjson })
937937+ |> Jsont.Object.opt_mem "proj:code" Jsont.string ~enc:(fun t -> t.code)
938938+ |> Jsont.Object.opt_mem "proj:wkt2" Jsont.string ~enc:(fun t -> t.wkt2)
939939+ |> Jsont.Object.opt_mem "proj:projjson" Jsont.json ~enc:(fun t -> t.projjson)
940940+ |> Jsont.Object.skip_unknown
941941+ |> Jsont.Object.finish
942942+ end
943943+944944+ module Spatial = struct
945945+ type t = {
946946+ dimensions : string list;
947947+ bbox : float list option;
948948+ transform_type : string option;
949949+ transform : float list option;
950950+ shape : int list option;
951951+ registration : [ `Pixel | `Node ] option;
952952+ }
953953+954954+ let dimensions t = t.dimensions
955955+ let bbox t = t.bbox
956956+ let transform_type t = t.transform_type
957957+ let transform t = t.transform
958958+ let shape t = t.shape
959959+ let registration t = t.registration
960960+961961+ let meta = { Meta.
962962+ uuid = "689b58e2-cf7b-45e0-9fff-9cfc0883d6b4";
963963+ name = "spatial:";
964964+ schema_url = Some "https://raw.githubusercontent.com/zarr-conventions/spatial/refs/tags/v1/schema.json";
965965+ spec_url = Some "https://github.com/zarr-conventions/spatial/blob/v1/README.md";
966966+ description = Some "Spatial coordinate information";
967967+ }
968968+969969+ let jsont =
970970+ let registration_jsont = Jsont.enum ~kind:"registration" ["pixel", `Pixel; "node", `Node] in
971971+ Jsont.Object.map ~kind:"Conv.Spatial"
972972+ (fun dimensions bbox transform_type transform shape registration ->
973973+ { dimensions; bbox; transform_type; transform; shape; registration })
974974+ |> Jsont.Object.mem "spatial:dimensions" (Jsont.list Jsont.string) ~enc:(fun t -> t.dimensions)
975975+ |> Jsont.Object.opt_mem "spatial:bbox" (Jsont.list Jsont.number) ~enc:(fun t -> t.bbox)
976976+ |> Jsont.Object.opt_mem "spatial:transform_type" Jsont.string ~enc:(fun t -> t.transform_type)
977977+ |> Jsont.Object.opt_mem "spatial:transform" (Jsont.list Jsont.number) ~enc:(fun t -> t.transform)
978978+ |> Jsont.Object.opt_mem "spatial:shape" (Jsont.list Jsont.int) ~enc:(fun t -> t.shape)
979979+ |> Jsont.Object.opt_mem "spatial:registration" registration_jsont ~enc:(fun t -> t.registration)
980980+ |> Jsont.Object.skip_unknown
981981+ |> Jsont.Object.finish
982982+ end
983983+984984+ module Multiscales = struct
985985+ module Transform = struct
986986+ type t = {
987987+ scale : float list option;
988988+ translation : float list option;
989989+ unknown : Jsont.json;
990990+ }
991991+992992+ let scale t = t.scale
993993+ let translation t = t.translation
994994+ let unknown t = t.unknown
995995+996996+ let jsont =
997997+ Jsont.Object.map ~kind:"Conv.Multiscales.Transform"
998998+ (fun scale translation unknown -> { scale; translation; unknown })
999999+ |> Jsont.Object.opt_mem "scale" (Jsont.list Jsont.number) ~enc:(fun t -> t.scale)
10001000+ |> Jsont.Object.opt_mem "translation" (Jsont.list Jsont.number) ~enc:(fun t -> t.translation)
10011001+ |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown)
10021002+ |> Jsont.Object.finish
10031003+ end
10041004+10051005+ module Layout_item = struct
10061006+ type t = {
10071007+ asset : string;
10081008+ derived_from : string option;
10091009+ transform : Transform.t option;
10101010+ resampling_method : string option;
10111011+ unknown : Jsont.json;
10121012+ }
10131013+10141014+ let asset t = t.asset
10151015+ let derived_from t = t.derived_from
10161016+ let transform t = t.transform
10171017+ let resampling_method t = t.resampling_method
10181018+ let unknown t = t.unknown
10191019+10201020+ let jsont =
10211021+ Jsont.Object.map ~kind:"Conv.Multiscales.Layout_item"
10221022+ (fun asset derived_from transform resampling_method unknown ->
10231023+ { asset; derived_from; transform; resampling_method; unknown })
10241024+ |> Jsont.Object.mem "asset" Jsont.string ~enc:(fun t -> t.asset)
10251025+ |> Jsont.Object.opt_mem "derived_from" Jsont.string ~enc:(fun t -> t.derived_from)
10261026+ |> Jsont.Object.opt_mem "transform" Transform.jsont ~enc:(fun t -> t.transform)
10271027+ |> Jsont.Object.opt_mem "resampling_method" Jsont.string ~enc:(fun t -> t.resampling_method)
10281028+ |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown)
10291029+ |> Jsont.Object.finish
10301030+ end
10311031+10321032+ type t = {
10331033+ layout : Layout_item.t list;
10341034+ resampling_method : string option;
10351035+ }
10361036+10371037+ let layout t = t.layout
10381038+ let resampling_method t = t.resampling_method
10391039+10401040+ let meta = { Meta.
10411041+ uuid = "d35379db-88df-4056-af3a-620245f8e347";
10421042+ name = "multiscales";
10431043+ schema_url = Some "https://raw.githubusercontent.com/zarr-conventions/multiscales/refs/tags/v1/schema.json";
10441044+ spec_url = Some "https://github.com/zarr-conventions/multiscales/blob/v1/README.md";
10451045+ description = Some "Multiscale layout of zarr datasets";
10461046+ }
10471047+10481048+ let jsont =
10491049+ Jsont.Object.map ~kind:"Conv.Multiscales"
10501050+ (fun layout resampling_method -> { layout; resampling_method })
10511051+ |> Jsont.Object.mem "layout" (Jsont.list Layout_item.jsont) ~enc:(fun t -> t.layout)
10521052+ |> Jsont.Object.opt_mem "resampling_method" Jsont.string ~enc:(fun t -> t.resampling_method)
10531053+ |> Jsont.Object.skip_unknown
10541054+ |> Jsont.Object.finish
10551055+ end
10561056+end
+68
src/zarr_jsont.mli
···269269 metadata object. The ["zarr_format"] field is consumed on decode and
270270 always written as [2] on encode. Unknown fields are preserved. *)
271271end
272272+273273+(** Zarr convention codecs.
274274+275275+ Provides metadata and typed codecs for known Zarr conventions.
276276+ Each sub-module exposes a [meta] constant describing the convention
277277+ and a [jsont] codec for its attributes. *)
278278+module Conv : sig
279279+ (** Convention registration metadata. *)
280280+ module Meta : sig
281281+ type t
282282+ val uuid : t -> string
283283+ val name : t -> string
284284+ val schema_url : t -> string option
285285+ val spec_url : t -> string option
286286+ val description : t -> string option
287287+ val jsont : t Jsont.t
288288+ end
289289+290290+ (** Geo-projection convention attributes ([proj:] prefix). *)
291291+ module Proj : sig
292292+ type t
293293+ val code : t -> string option
294294+ val wkt2 : t -> string option
295295+ val projjson : t -> Jsont.json option
296296+ val meta : Meta.t
297297+ val jsont : t Jsont.t
298298+ end
299299+300300+ (** Spatial convention attributes ([spatial:] prefix). *)
301301+ module Spatial : sig
302302+ type t
303303+ val dimensions : t -> string list
304304+ val bbox : t -> float list option
305305+ val transform_type : t -> string option
306306+ val transform : t -> float list option
307307+ val shape : t -> int list option
308308+ val registration : t -> [ `Pixel | `Node ] option
309309+ val meta : Meta.t
310310+ val jsont : t Jsont.t
311311+ end
312312+313313+ (** Multiscales convention attributes. *)
314314+ module Multiscales : sig
315315+ (** Coordinate transform for a layout item. *)
316316+ module Transform : sig
317317+ type t
318318+ val scale : t -> float list option
319319+ val translation : t -> float list option
320320+ val unknown : t -> Jsont.json
321321+ end
322322+323323+ (** A single entry in the multiscales layout. *)
324324+ module Layout_item : sig
325325+ type t
326326+ val asset : t -> string
327327+ val derived_from : t -> string option
328328+ val transform : t -> Transform.t option
329329+ val resampling_method : t -> string option
330330+ val unknown : t -> Jsont.json
331331+ end
332332+333333+ type t
334334+ val layout : t -> Layout_item.t list
335335+ val resampling_method : t -> string option
336336+ val meta : Meta.t
337337+ val jsont : t Jsont.t
338338+ end
339339+end
+43
test/test_zarr_jsont.ml
···273273 | _ -> assert false);
274274 print_endline "test_v3_array_meta: ok"
275275276276+let test_conv_proj () =
277277+ let json = {|{"proj:code":"EPSG:4326","other_key":"ignored"}|} in
278278+ let v = decode Zarr_jsont.Conv.Proj.jsont json in
279279+ assert (Zarr_jsont.Conv.Proj.code v = Some "EPSG:4326");
280280+ assert (Zarr_jsont.Conv.Proj.wkt2 v = None);
281281+ assert (Zarr_jsont.Conv.Proj.projjson v = None);
282282+ print_endline "test_conv_proj: ok"
283283+284284+let test_conv_spatial () =
285285+ let json = {|{
286286+ "spatial:dimensions": ["Y", "X"],
287287+ "spatial:bbox": [-180.0, -90.0, 180.0, 90.0],
288288+ "spatial:transform": [1.0, 0.0, 0.0, 0.0, -1.0, 90.0],
289289+ "spatial:registration": "pixel"
290290+ }|} in
291291+ let v = decode Zarr_jsont.Conv.Spatial.jsont json in
292292+ assert (Zarr_jsont.Conv.Spatial.dimensions v = ["Y"; "X"]);
293293+ assert (Zarr_jsont.Conv.Spatial.registration v = Some `Pixel);
294294+ assert (Zarr_jsont.Conv.Spatial.bbox v = Some [-180.0; -90.0; 180.0; 90.0]);
295295+ print_endline "test_conv_spatial: ok"
296296+297297+let test_conv_multiscales () =
298298+ let json = {|{
299299+ "layout": [
300300+ {"asset": "0", "transform": {"scale": [1.0, 1.0]}},
301301+ {"asset": "1", "derived_from": "0", "transform": {"scale": [2.0, 2.0]}, "resampling_method": "average"}
302302+ ],
303303+ "resampling_method": "average"
304304+ }|} in
305305+ let v = decode Zarr_jsont.Conv.Multiscales.jsont json in
306306+ let layout = Zarr_jsont.Conv.Multiscales.layout v in
307307+ assert (List.length layout = 2);
308308+ let item0 = List.nth layout 0 in
309309+ assert (Zarr_jsont.Conv.Multiscales.Layout_item.asset item0 = "0");
310310+ assert (Zarr_jsont.Conv.Multiscales.Layout_item.derived_from item0 = None);
311311+ let item1 = List.nth layout 1 in
312312+ assert (Zarr_jsont.Conv.Multiscales.Layout_item.derived_from item1 = Some "0");
313313+ assert (Zarr_jsont.Conv.Multiscales.Layout_item.resampling_method item1 = Some "average");
314314+ print_endline "test_conv_multiscales: ok"
315315+276316let () = test_other_codec ()
277317let () = test_other_ext ()
278318let () = test_fill_value ()
···283323let () = test_v3_codecs ()
284324let () = test_v3_data_type ()
285325let () = test_v3_array_meta ()
326326+let () = test_conv_proj ()
327327+let () = test_conv_spatial ()
328328+let () = test_conv_multiscales ()