From 10690182ac79a63cf139aa38620b26a6a2cd8c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20Fern=C3=A1ndez?= Date: Fri, 3 Dec 2021 22:07:08 +0100 Subject: [PATCH 1/4] Add support for 64-bit integers. --- README.md | 3 +++ examples/async/nonblocking_async_example.ml | 1 + examples/blocking/blocking_example.ml | 1 + examples/lwt/nonblocking_lwt_example.ml | 1 + examples/select/nonblocking_select_example.ml | 1 + lib/bind.ml | 9 +++++++++ lib/common.ml | 1 + lib/field.ml | 16 ++++++++++++++-- lib/mariadb.ml | 3 +++ lib/mariadb.mli | 4 ++++ lib/nonblocking.ml | 1 + tests/nonblocking/nonblocking_testsuite.ml | 4 ++++ 12 files changed, 43 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 584a440..e7b63be 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,7 @@ function. ```ocaml type value = [ `Int of int + | `Int64 of Int64.t | `Float of float | `String of string | `Bytes of bytes @@ -221,6 +222,7 @@ provided to extract the OCaml types directly from a field: ```ocaml val int : Field.t -> int +val int64 : Field.t -> Int64.t val float : Field.t -> float val string : Field.t -> string val bytes : Field.t -> bytes @@ -234,6 +236,7 @@ For nullable fields, the following analogous functions are also provided: ```ocaml val int_opt : Field.t -> int option +val int64_opt : Field.t -> Int64.t option val float_opt : Field.t -> float option val string_opt : Field.t -> string option val bytes_opt : Field.t -> bytes option diff --git a/examples/async/nonblocking_async_example.ml b/examples/async/nonblocking_async_example.ml index 71196ad..544cf58 100644 --- a/examples/async/nonblocking_async_example.ml +++ b/examples/async/nonblocking_async_example.ml @@ -66,6 +66,7 @@ let print_row row = printf "%20s " name; match M.Field.value field with | `Int i -> printf "%d\n%!" i + | `Int64 i -> printf "%Ld\n%!" i | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Caml_bytes.to_string b) diff --git a/examples/blocking/blocking_example.ml b/examples/blocking/blocking_example.ml index 81de5dd..72674a1 100644 --- a/examples/blocking/blocking_example.ml +++ b/examples/blocking/blocking_example.ml @@ -17,6 +17,7 @@ let print_row row = printf "%20s " name; match M.Field.value field with | `Int i -> printf "%d\n%!" i + | `Int64 i -> printf "%Ld\n%!" i | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Bytes.to_string b) diff --git a/examples/lwt/nonblocking_lwt_example.ml b/examples/lwt/nonblocking_lwt_example.ml index 4602598..efab2e2 100644 --- a/examples/lwt/nonblocking_lwt_example.ml +++ b/examples/lwt/nonblocking_lwt_example.ml @@ -52,6 +52,7 @@ let print_row row = Lwt_io.printf "%20s " name >>= fun () -> match M.Field.value field with | `Int i -> Lwt_io.printf "%d\n%!" i + | `Int64 i -> Lwt_io.printf "%Ld\n%!" i | `Float x -> Lwt_io.printf "%f\n%!" x | `String s -> Lwt_io.printf "%s\n%!" s | `Bytes b -> Lwt_io.printf "%s\n%!" (Bytes.to_string b) diff --git a/examples/select/nonblocking_select_example.ml b/examples/select/nonblocking_select_example.ml index f8ad038..70a446c 100644 --- a/examples/select/nonblocking_select_example.ml +++ b/examples/select/nonblocking_select_example.ml @@ -55,6 +55,7 @@ let print_row row = printf "%20s " name; match M.Field.value field with | `Int i -> printf "%d\n%!" i + | `Int64 i -> printf "%Ld\n%!" i | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Bytes.to_string b) diff --git a/lib/bind.ml b/lib/bind.ml index 4927f86..b7c9ef7 100644 --- a/lib/bind.ml +++ b/lib/bind.ml @@ -124,6 +124,15 @@ let int ?(unsigned = false) b param ~at = ~unsigned:(if unsigned then yes else no) ~at +let int64 ?(unsigned = false) b param ~at = + let p = allocate int64_t param in + bind b + ~buffer:(coerce (ptr int64_t) (ptr void) p) + ~size:(sizeof int64_t) + ~mysql_type:T.Type.long_long + ~unsigned:(if unsigned then yes else no) + ~at + let float b param ~at = let p = allocate float param in bind b diff --git a/lib/common.ml b/lib/common.ml index 397df26..1804caf 100644 --- a/lib/common.ml +++ b/lib/common.ml @@ -323,6 +323,7 @@ module Stmt = struct match arg with | `Null -> Bind.null b ~at | `Int i -> Bind.int b i ~at + | `Int64 i -> Bind.int64 b i ~at | `Float x -> Bind.float b x ~at | `String s -> Bind.string b s ~at | `Bytes s -> Bind.blob b s ~at diff --git a/lib/field.ml b/lib/field.ml index 7bd383e..07a4f35 100644 --- a/lib/field.ml +++ b/lib/field.ml @@ -5,6 +5,7 @@ module T = Ffi_generated.Types type value = [ `Null | `Int of int + | `Int64 of Int64.t | `Float of float | `String of string | `Bytes of bytes @@ -81,8 +82,8 @@ let convert field typ unsigned = | `Short, false -> `Int (UInt.to_int (cast_to uint field)) | (`Int24 | `Long), true -> `Int (UInt32.to_int (cast_to uint32_t field)) | (`Int24 | `Long), false -> `Int (Int32.to_int (cast_to int32_t field)) - | `Long_long, true -> `Int (UInt64.to_int (cast_to uint64_t field)) - | `Long_long, false -> `Int (Int64.to_int (cast_to int64_t field)) + | `Long_long, true -> `Int64 (UInt64.to_int64 (cast_to uint64_t field)) + | `Long_long, false -> `Int64 (cast_to int64_t field) | `Float, _ -> `Float (cast_to float field) | `Double, _ -> `Float (cast_to double field) | #to_string, _ -> `String (Bytes.to_string (to_bytes field)) @@ -104,6 +105,11 @@ let int field = | `Int i -> i | _ -> err field ~info:"an integer" +let int64 field = + match value field with + | `Int64 i -> i + | _ -> err field ~info:"an 64-bit integer" + let float field = match value field with | `Float x -> x @@ -130,6 +136,12 @@ let int_opt field = | `Null -> None | _ -> err field ~info:"a nullable integer" +let int64_opt field = + match value field with + | `Int64 i -> Some i + | `Null -> None + | _ -> err field ~info:"a nullable 64-bit integer" + let float_opt field = match value field with | `Float x -> Some x diff --git a/lib/mariadb.ml b/lib/mariadb.ml index 85b7be9..b18b1cd 100644 --- a/lib/mariadb.ml +++ b/lib/mariadb.ml @@ -29,6 +29,7 @@ module type S = sig type value = [ `Null | `Int of int + | `Int64 of int64 | `Float of float | `String of string | `Bytes of bytes @@ -41,12 +42,14 @@ module type S = sig val can_be_null : t -> bool val int : t -> int + val int64 : t -> Int64.t val float : t -> float val string : t -> string val bytes : t -> bytes val time : t -> Time.t val int_opt : t -> int option + val int64_opt : t -> Int64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option diff --git a/lib/mariadb.mli b/lib/mariadb.mli index 0e39c8d..121575f 100644 --- a/lib/mariadb.mli +++ b/lib/mariadb.mli @@ -51,6 +51,7 @@ module type S = sig type value = [ `Null | `Int of int + | `Int64 of Int64.t | `Float of float | `String of string | `Bytes of bytes @@ -81,12 +82,14 @@ module type S = sig *) val int : t -> int + val int64 : t -> Int64.t val float : t -> float val string : t -> string val bytes : t -> bytes val time : t -> Time.t val int_opt : t -> int option + val int64_opt : t -> Int64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option @@ -385,6 +388,7 @@ module Nonblocking : sig type value = [ `Null | `Int of int + | `Int64 of Int64.t | `Float of float | `String of string | `Bytes of bytes diff --git a/lib/nonblocking.ml b/lib/nonblocking.ml index 0184ff2..49e4ee9 100644 --- a/lib/nonblocking.ml +++ b/lib/nonblocking.ml @@ -398,6 +398,7 @@ module type S = sig type value = [ `Null | `Int of int + | `Int64 of Int64.t | `Float of float | `String of string | `Bytes of bytes diff --git a/tests/nonblocking/nonblocking_testsuite.ml b/tests/nonblocking/nonblocking_testsuite.ml index c186f9a..81dc254 100644 --- a/tests/nonblocking/nonblocking_testsuite.ml +++ b/tests/nonblocking/nonblocking_testsuite.ml @@ -86,6 +86,7 @@ struct let string_of_value = function | `Null -> "NULL" | `Int i -> sprintf "(%d : int)" i + | `Int64 i -> sprintf "(%Ld : int64)" i | `Float x -> sprintf "(%.8g : float)" x | `String s -> sprintf "(%S : string)" s | `Bytes s -> sprintf "(%S : bytes)" (Bytes.to_string s) @@ -106,7 +107,10 @@ struct | `Null, _ | _, `Null -> false | `Int i, `Int i' -> i = i' | `Int i, `Float x | `Float x, `Int i -> float_of_int i = x + | `Int64 i, `Int x | `Int x, `Int64 i -> Int64.(equal i (of_int x)) + | `Int64 i, `Float x | `Float x, `Int64 i -> Int64.to_float i = x | `Int _, _ | _, `Int _ -> false + | `Int64 _, _ | _, `Int64 _ -> false | `Float x, `Float x' -> equal_float x x' | `Float _, _ | _, `Float _ -> false | `String s, `String s' -> s = s' From 5dea9176f6c4037c38ca89c805134a42dc1088d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20Fern=C3=A1ndez?= Date: Fri, 3 Dec 2021 23:18:47 +0100 Subject: [PATCH 2/4] Add support for binding 64-bit unsigned params. --- lib/common.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common.ml b/lib/common.ml index 1804caf..e7ee71e 100644 --- a/lib/common.ml +++ b/lib/common.ml @@ -324,6 +324,7 @@ module Stmt = struct | `Null -> Bind.null b ~at | `Int i -> Bind.int b i ~at | `Int64 i -> Bind.int64 b i ~at + | `UInt64 i -> Bind.int64 ~unsigned:true b i ~at | `Float x -> Bind.float b x ~at | `String s -> Bind.string b s ~at | `Bytes s -> Bind.blob b s ~at From d96f50da8f93ab48758bf5be4c9926f5b63c898e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20Fern=C3=A1ndez?= Date: Sat, 4 Dec 2021 00:13:18 +0100 Subject: [PATCH 3/4] Support 64-bit unsigned fields. --- README.md | 3 +++ examples/async/nonblocking_async_example.ml | 1 + examples/blocking/blocking_example.ml | 1 + examples/lwt/nonblocking_lwt_example.ml | 1 + examples/select/nonblocking_select_example.ml | 1 + lib/common.ml | 2 +- lib/field.ml | 16 ++++++++++++++-- lib/mariadb.ml | 5 ++++- lib/mariadb.mli | 8 ++++++++ lib/nonblocking.ml | 5 +++++ tests/nonblocking/nonblocking_testsuite.ml | 5 +++++ 11 files changed, 44 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e7b63be..bef6e30 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,7 @@ function. type value = [ `Int of int | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -223,6 +224,7 @@ provided to extract the OCaml types directly from a field: ```ocaml val int : Field.t -> int val int64 : Field.t -> Int64.t +val uint64 : Field.t -> Unsigned.Int64.t val float : Field.t -> float val string : Field.t -> string val bytes : Field.t -> bytes @@ -237,6 +239,7 @@ For nullable fields, the following analogous functions are also provided: ```ocaml val int_opt : Field.t -> int option val int64_opt : Field.t -> Int64.t option +val uint64_opt : Field.t -> Unsigned.UInt64.t option val float_opt : Field.t -> float option val string_opt : Field.t -> string option val bytes_opt : Field.t -> bytes option diff --git a/examples/async/nonblocking_async_example.ml b/examples/async/nonblocking_async_example.ml index 544cf58..7037915 100644 --- a/examples/async/nonblocking_async_example.ml +++ b/examples/async/nonblocking_async_example.ml @@ -67,6 +67,7 @@ let print_row row = match M.Field.value field with | `Int i -> printf "%d\n%!" i | `Int64 i -> printf "%Ld\n%!" i + | `UInt64 i -> printf "%s\n%!" (Unsigned.UInt64.to_string i) | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Caml_bytes.to_string b) diff --git a/examples/blocking/blocking_example.ml b/examples/blocking/blocking_example.ml index 72674a1..c4400e3 100644 --- a/examples/blocking/blocking_example.ml +++ b/examples/blocking/blocking_example.ml @@ -18,6 +18,7 @@ let print_row row = match M.Field.value field with | `Int i -> printf "%d\n%!" i | `Int64 i -> printf "%Ld\n%!" i + | `UInt64 i -> printf "%s\n%!" (Unsigned.UInt64.to_string i) | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Bytes.to_string b) diff --git a/examples/lwt/nonblocking_lwt_example.ml b/examples/lwt/nonblocking_lwt_example.ml index efab2e2..49b7fbf 100644 --- a/examples/lwt/nonblocking_lwt_example.ml +++ b/examples/lwt/nonblocking_lwt_example.ml @@ -53,6 +53,7 @@ let print_row row = match M.Field.value field with | `Int i -> Lwt_io.printf "%d\n%!" i | `Int64 i -> Lwt_io.printf "%Ld\n%!" i + | `UInt64 i -> Lwt_io.printf "%s\n%!" (Unsigned.UInt64.to_string i) | `Float x -> Lwt_io.printf "%f\n%!" x | `String s -> Lwt_io.printf "%s\n%!" s | `Bytes b -> Lwt_io.printf "%s\n%!" (Bytes.to_string b) diff --git a/examples/select/nonblocking_select_example.ml b/examples/select/nonblocking_select_example.ml index 70a446c..4ad01b8 100644 --- a/examples/select/nonblocking_select_example.ml +++ b/examples/select/nonblocking_select_example.ml @@ -56,6 +56,7 @@ let print_row row = match M.Field.value field with | `Int i -> printf "%d\n%!" i | `Int64 i -> printf "%Ld\n%!" i + | `UInt64 i -> printf "%s\n%!" (Unsigned.UInt64.to_string i) | `Float x -> printf "%f\n%!" x | `String s -> printf "%s\n%!" s | `Bytes b -> printf "%s\n%!" (Bytes.to_string b) diff --git a/lib/common.ml b/lib/common.ml index e7ee71e..39ae627 100644 --- a/lib/common.ml +++ b/lib/common.ml @@ -324,7 +324,7 @@ module Stmt = struct | `Null -> Bind.null b ~at | `Int i -> Bind.int b i ~at | `Int64 i -> Bind.int64 b i ~at - | `UInt64 i -> Bind.int64 ~unsigned:true b i ~at + | `UInt64 i -> Bind.int64 ~unsigned:true b (Unsigned.UInt64.to_int64 i) ~at | `Float x -> Bind.float b x ~at | `String s -> Bind.string b s ~at | `Bytes s -> Bind.blob b s ~at diff --git a/lib/field.ml b/lib/field.ml index 07a4f35..4a448fb 100644 --- a/lib/field.ml +++ b/lib/field.ml @@ -6,6 +6,7 @@ type value = [ `Null | `Int of int | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -82,7 +83,7 @@ let convert field typ unsigned = | `Short, false -> `Int (UInt.to_int (cast_to uint field)) | (`Int24 | `Long), true -> `Int (UInt32.to_int (cast_to uint32_t field)) | (`Int24 | `Long), false -> `Int (Int32.to_int (cast_to int32_t field)) - | `Long_long, true -> `Int64 (UInt64.to_int64 (cast_to uint64_t field)) + | `Long_long, true -> `UInt64 (cast_to uint64_t field) | `Long_long, false -> `Int64 (cast_to int64_t field) | `Float, _ -> `Float (cast_to float field) | `Double, _ -> `Float (cast_to double field) @@ -108,7 +109,12 @@ let int field = let int64 field = match value field with | `Int64 i -> i - | _ -> err field ~info:"an 64-bit integer" + | _ -> err field ~info:"a 64-bit integer" + +let uint64 field = + match value field with + | `UInt64 i -> i + | _ -> err field ~info:"a 64-bit unsigned integer" let float field = match value field with @@ -142,6 +148,12 @@ let int64_opt field = | `Null -> None | _ -> err field ~info:"a nullable 64-bit integer" +let uint64_opt field = + match value field with + | `UInt64 i -> Some i + | `Null -> None + | _ -> err field ~info:"a nullable 64-bit unsigned integer" + let float_opt field = match value field with | `Float x -> Some x diff --git a/lib/mariadb.ml b/lib/mariadb.ml index b18b1cd..5ca6e36 100644 --- a/lib/mariadb.ml +++ b/lib/mariadb.ml @@ -29,7 +29,8 @@ module type S = sig type value = [ `Null | `Int of int - | `Int64 of int64 + | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -43,6 +44,7 @@ module type S = sig val int : t -> int val int64 : t -> Int64.t + val uint64 : t -> Unsigned.UInt64.t val float : t -> float val string : t -> string val bytes : t -> bytes @@ -50,6 +52,7 @@ module type S = sig val int_opt : t -> int option val int64_opt : t -> Int64.t option + val uint64_opt : t -> Unsigned.UInt64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option diff --git a/lib/mariadb.mli b/lib/mariadb.mli index 121575f..4cc78c8 100644 --- a/lib/mariadb.mli +++ b/lib/mariadb.mli @@ -52,6 +52,7 @@ module type S = sig [ `Null | `Int of int | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -83,6 +84,7 @@ module type S = sig val int : t -> int val int64 : t -> Int64.t + val uint64 : t -> Unsigned.UInt64.t val float : t -> float val string : t -> string val bytes : t -> bytes @@ -90,6 +92,7 @@ module type S = sig val int_opt : t -> int option val int64_opt : t -> Int64.t option + val uint64_opt : t -> Unsigned.UInt64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option @@ -389,6 +392,7 @@ module Nonblocking : sig [ `Null | `Int of int | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -401,12 +405,16 @@ module Nonblocking : sig val can_be_null : t -> bool val int : t -> int + val int64 : t -> Int64.t + val uint64 : t -> Unsigned.UInt64.t val float : t -> float val string : t -> string val bytes : t -> bytes val time : t -> Time.t val int_opt : t -> int option + val int64_opt : t -> Int64.t option + val uint64_opt : t -> Unsigned.UInt64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option diff --git a/lib/nonblocking.ml b/lib/nonblocking.ml index 49e4ee9..32b2321 100644 --- a/lib/nonblocking.ml +++ b/lib/nonblocking.ml @@ -399,6 +399,7 @@ module type S = sig [ `Null | `Int of int | `Int64 of Int64.t + | `UInt64 of Unsigned.UInt64.t | `Float of float | `String of string | `Bytes of bytes @@ -411,12 +412,16 @@ module type S = sig val can_be_null : t -> bool val int : t -> int + val int64 : t -> Int64.t + val uint64 : t -> Unsigned.UInt64.t val float : t -> float val string : t -> string val bytes : t -> bytes val time : t -> Time.t val int_opt : t -> int option + val int64_opt : t -> Int64.t option + val uint64_opt : t -> Unsigned.UInt64.t option val float_opt : t -> float option val string_opt : t -> string option val bytes_opt : t -> bytes option diff --git a/tests/nonblocking/nonblocking_testsuite.ml b/tests/nonblocking/nonblocking_testsuite.ml index 81dc254..3192324 100644 --- a/tests/nonblocking/nonblocking_testsuite.ml +++ b/tests/nonblocking/nonblocking_testsuite.ml @@ -87,6 +87,7 @@ struct | `Null -> "NULL" | `Int i -> sprintf "(%d : int)" i | `Int64 i -> sprintf "(%Ld : int64)" i + | `UInt64 i -> sprintf "(%s : uint64)" (Unsigned.UInt64.to_string i) | `Float x -> sprintf "(%.8g : float)" x | `String s -> sprintf "(%S : string)" s | `Bytes s -> sprintf "(%S : bytes)" (Bytes.to_string s) @@ -109,8 +110,12 @@ struct | `Int i, `Float x | `Float x, `Int i -> float_of_int i = x | `Int64 i, `Int x | `Int x, `Int64 i -> Int64.(equal i (of_int x)) | `Int64 i, `Float x | `Float x, `Int64 i -> Int64.to_float i = x + | `UInt64 i, `Int x | `Int x, `UInt64 i -> Unsigned.UInt64.(equal i (of_int x)) + | `UInt64 i, `Float x | `Float x, `UInt64 i -> Int64.to_float (Unsigned.UInt64.to_int64 i) = x + | `UInt64 i, `Int64 x | `Int64 x, `UInt64 i -> Int64.equal (Unsigned.UInt64.to_int64 i) x | `Int _, _ | _, `Int _ -> false | `Int64 _, _ | _, `Int64 _ -> false + | `UInt64 _, _ | _, `UInt64 _ -> false | `Float x, `Float x' -> equal_float x x' | `Float _, _ | _, `Float _ -> false | `String s, `String s' -> s = s' From d69aeed8abb32066dd6549114d047c68af447d08 Mon Sep 17 00:00:00 2001 From: "Petter A. Urkedal" Date: Thu, 28 Nov 2024 10:57:00 +0100 Subject: [PATCH 4/4] Allow more conversions for integer extractors. - Field.int: Accept conversions from 64 bit integers. This can overflow, but on 64 bit platforms there is a large usable range which has been accepted in the past. We may consider adding overflow detection, though. - Field.int64: Accept conversions from smaller integers. --- lib/field.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/field.ml b/lib/field.ml index 4a448fb..b3ee12a 100644 --- a/lib/field.ml +++ b/lib/field.ml @@ -104,10 +104,13 @@ let err field ~info = let int field = match value field with | `Int i -> i + | `Int64 i -> Int64.to_int i + | `UInt64 i -> Unsigned.UInt64.to_int i | _ -> err field ~info:"an integer" let int64 field = match value field with + | `Int i -> Int64.of_int i | `Int64 i -> i | _ -> err field ~info:"a 64-bit integer" @@ -139,11 +142,14 @@ let time field = let int_opt field = match value field with | `Int i -> Some i + | `Int64 i -> Some (Int64.to_int i) + | `UInt64 i -> Some (Unsigned.UInt64.to_int i) | `Null -> None | _ -> err field ~info:"a nullable integer" let int64_opt field = match value field with + | `Int i -> Some (Int64.of_int i) | `Int64 i -> Some i | `Null -> None | _ -> err field ~info:"a nullable 64-bit integer"