···1414 |> Jsont.Object.finish
1515end
16161717+type fill_value = [
1818+ | `Null
1919+ | `Bool of bool
2020+ | `Int of int64
2121+ | `Float of float
2222+ | `Complex of float * float
2323+ | `Bytes of string
2424+]
2525+2626+let fill_value_jsont =
2727+ (* Decode a float from a JSON number, deciding if it should be `Int or `Float *)
2828+ let dec_number_to_fill f =
2929+ if Float.is_finite f && Float.is_integer f && f >= Int64.(to_float min_int) && f <= Int64.(to_float max_int)
3030+ then `Int (Int64.of_float f)
3131+ else `Float f
3232+ in
3333+ let number_codec =
3434+ Jsont.map ~kind:"fill_value_number"
3535+ ~dec:dec_number_to_fill
3636+ ~enc:(function
3737+ | `Int i -> Int64.to_float i
3838+ | `Float f -> f
3939+ | _ -> assert false)
4040+ Jsont.number
4141+ in
4242+ let string_codec =
4343+ Jsont.map ~kind:"fill_value_string"
4444+ ~dec:(fun s -> match s with
4545+ | "NaN" -> `Float Float.nan
4646+ | "Infinity" -> `Float Float.infinity
4747+ | "-Infinity" -> `Float Float.neg_infinity
4848+ | _ when String.length s > 2 && s.[0] = '0' && (s.[1] = 'x' || s.[1] = 'X') ->
4949+ let i = Int64.of_string s in
5050+ `Float (Int64.to_float i)
5151+ | _ -> `Bytes s)
5252+ ~enc:(function
5353+ | `Float f when Float.is_nan f -> "NaN"
5454+ | `Float f when f = Float.infinity -> "Infinity"
5555+ | `Float f when f = Float.neg_infinity -> "-Infinity"
5656+ | `Bytes s -> s
5757+ | _ -> assert false)
5858+ Jsont.string
5959+ in
6060+ (* Array codec: either complex (2 floats) or bytes (list of ints 0-255) *)
6161+ let array_codec =
6262+ Jsont.map ~kind:"fill_value_array"
6363+ ~dec:(fun fs -> match fs with
6464+ | [r; i] -> `Complex (r, i)
6565+ | bs ->
6666+ let buf = Bytes.create (List.length bs) in
6767+ List.iteri (fun idx b -> Bytes.set buf idx (Char.chr (int_of_float b))) bs;
6868+ `Bytes (Bytes.to_string buf))
6969+ ~enc:(function
7070+ | `Complex (r, i) -> [r; i]
7171+ | `Bytes s ->
7272+ String.to_seq s |> Seq.map (fun c -> float_of_int (Char.code c)) |> List.of_seq
7373+ | _ -> assert false)
7474+ (Jsont.list Jsont.number)
7575+ in
7676+ Jsont.any ~kind:"fill_value"
7777+ ~dec_null:(Jsont.null `Null)
7878+ ~dec_bool:(Jsont.map ~kind:"fill_value_bool" ~dec:(fun b -> `Bool b) ~enc:(function `Bool b -> b | _ -> assert false) Jsont.bool)
7979+ ~dec_number:number_codec
8080+ ~dec_string:string_codec
8181+ ~dec_array:array_codec
8282+ ~enc:(function
8383+ | `Null -> Jsont.null `Null
8484+ | `Bool _ -> Jsont.map ~kind:"fill_value_bool" ~dec:(fun b -> `Bool b) ~enc:(function `Bool b -> b | _ -> assert false) Jsont.bool
8585+ | `Int _ -> number_codec
8686+ | `Float f when Float.is_nan f || not (Float.is_finite f) -> string_codec
8787+ | `Float _ -> number_codec
8888+ | `Complex _ -> array_codec
8989+ | `Bytes _ -> array_codec)
9090+ ()
9191+1792module Other_ext = struct
1893 type t = { name : string; configuration : Jsont.json option; must_understand : bool }
1994
+19
src/zarr_jsont.mli
···11(** Jsont codecs for Zarr v2 and v3 metadata. *)
2233+(** Polymorphic fill value shared between Zarr v2 and v3 array metadata.
44+55+ Encodes the value stored in unwritten or missing chunks. The JSON
66+ representation is flexible: null, boolean, integer number, floating-point
77+ number (including the special strings ["NaN"], ["Infinity"],
88+ ["-Infinity"]), a two-element array for complex numbers, or an integer
99+ array (0–255) for raw bytes. *)
1010+type fill_value = [
1111+ | `Null
1212+ | `Bool of bool
1313+ | `Int of int64
1414+ | `Float of float
1515+ | `Complex of float * float
1616+ | `Bytes of string
1717+]
1818+1919+val fill_value_jsont : fill_value Jsont.t
2020+(** Codec for {!fill_value}. Dispatches on the JSON sort via {!Jsont.any}. *)
2121+322(** Catch-all type for unrecognized v2 codecs.
423524 Represents objects with an ["id"] key plus arbitrary extra fields,
+32
test/test_zarr_jsont.ml
···2424 assert (Zarr_jsont.Other_ext.name v' = "custom.ext");
2525 print_endline "test_other_ext: ok"
26262727+let test_fill_value () =
2828+ let fv = Zarr_jsont.fill_value_jsont in
2929+ (* null *)
3030+ let v = decode fv "null" in
3131+ assert (v = `Null);
3232+ (* bool *)
3333+ let v = decode fv "true" in
3434+ assert (v = `Bool true);
3535+ (* int *)
3636+ let v = decode fv "42" in
3737+ assert (v = `Int 42L);
3838+ (* float *)
3939+ let v = decode fv "3.14" in
4040+ (match v with `Float f -> assert (f = 3.14) | _ -> assert false);
4141+ (* NaN string *)
4242+ let v = decode fv {|"NaN"|} in
4343+ (match v with `Float f -> assert (Float.is_nan f) | _ -> assert false);
4444+ (* Infinity string *)
4545+ let v = decode fv {|"Infinity"|} in
4646+ (match v with `Float f -> assert (f = infinity) | _ -> assert false);
4747+ (* -Infinity string *)
4848+ let v = decode fv {|"-Infinity"|} in
4949+ (match v with `Float f -> assert (f = neg_infinity) | _ -> assert false);
5050+ (* complex as array *)
5151+ let v = decode fv {|[1.0, 2.0]|} in
5252+ assert (v = `Complex (1.0, 2.0));
5353+ (* bytes as int array *)
5454+ let v = decode fv {|[0, 255, 128]|} in
5555+ (match v with `Bytes s -> assert (String.length s = 3) | _ -> assert false);
5656+ print_endline "test_fill_value: ok"
5757+2758let () = test_other_codec ()
2859let () = test_other_ext ()
6060+let () = test_fill_value ()