[Libguestfs] [libnbd PATCH 1/3] generator: Introduce REnum/RFlags return types

Eric Blake eblake at redhat.com
Sun Sep 6 01:40:58 UTC 2020


For now, there is no change to the generated code (although the man
pages are slightly improved), but this will make it easier for later
patches to improve OCaml and Golang bindings so that set/get pairs are
typed symmetrically.
---
 generator/API.ml    | 16 ++++++++++------
 generator/API.mli   |  2 ++
 generator/C.ml      | 20 ++++++++++++--------
 generator/GoLang.ml | 13 ++++++++++++-
 generator/OCaml.ml  |  4 ++++
 generator/Python.ml |  2 ++
 6 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/generator/API.ml b/generator/API.ml
index 962b787..bf6030f 100644
--- a/generator/API.ml
+++ b/generator/API.ml
@@ -66,6 +66,8 @@ and ret =
 | RCookie
 | RString
 | RUInt
+| REnum of enum
+| RFlags of flags
 and closure = {
   cbname : string;
   cbargs : cbarg list;
@@ -442,7 +444,7 @@ test whether this is the case with L<nbd_supports_tls(3)>.";

   "get_tls", {
     default_call with
-    args = []; ret = RInt;
+    args = []; ret = REnum (tls_enum);
     may_set_error = false;
     shortdesc = "get the TLS request setting";
     longdesc = "\
@@ -678,7 +680,7 @@ Future NBD extensions may add further flags.

   "get_handshake_flags", {
     default_call with
-    args = []; ret = RUInt;
+    args = []; ret = RFlags (handshake_flags);
     may_set_error = false;
     shortdesc = "see which handshake flags are supported";
     longdesc = "\
@@ -2708,11 +2710,13 @@ let () =
        failwithf "%s: if may_set_error is false, permitted_states must be empty (any permitted state)"
                  name

-    (* may_set_error = true is incompatible with RUInt because
-     * these calls cannot return an error indication.
+    (* may_set_error = true is incompatible with RUInt, REnum, and RFlags
+     * because these calls cannot return an error indication.
      *)
-    | name, { ret = RUInt; may_set_error = true } ->
-       failwithf "%s: if ret is RUInt, may_set_error must be false" name
+    | name, { ret = RUInt; may_set_error = true }
+    | name, { ret = REnum (_); may_set_error = true }
+    | name, { ret = RFlags (_); may_set_error = true } ->
+       failwithf "%s: if ret is RUInt/REnum/RFlags, may_set_error must be false" name

     (* !may_set_error is incompatible with certain parameters because
      * we have to do a NULL-check on those which may return an error.
diff --git a/generator/API.mli b/generator/API.mli
index 712e837..e45b5c0 100644
--- a/generator/API.mli
+++ b/generator/API.mli
@@ -78,6 +78,8 @@ and ret =
 | RString                  (** return a newly allocated string,
                                caller frees, NULL for error *)
 | RUInt                    (** return a bitmask, no error possible *)
+| REnum of enum            (** return an enum, no error possible *)
+| RFlags of flags          (** return bitmask of flags, no error possible *)
 and closure = {
   cbname : string;         (** name of callback function *)
   cbargs : cbarg list;     (** all closures return int for now *)
diff --git a/generator/C.ml b/generator/C.ml
index 6b65f6e..1eb5e85 100644
--- a/generator/C.ml
+++ b/generator/C.ml
@@ -66,15 +66,15 @@ let errcode_of_ret =
   function
   | RBool | RErr | RFd | RInt | RInt64 | RCookie -> Some "-1"
   | RStaticString | RString -> Some "NULL"
-  | RUInt -> None (* errors not possible *)
+  | RUInt | REnum (_) | RFlags (_) -> None (* errors not possible *)

 let type_of_ret =
   function
-  | RBool | RErr | RFd | RInt -> "int"
+  | RBool | RErr | RFd | RInt | REnum (_) -> "int"
   | RInt64 | RCookie -> "int64_t"
   | RStaticString -> "const char *"
   | RString -> "char *"
-  | RUInt -> "unsigned"
+  | RUInt | RFlags (_) -> "unsigned"

 let rec name_of_arg = function
 | Bool n -> [n]
@@ -664,22 +664,22 @@ let generate_lib_api_c () =
         pr "          nbd_internal_printable_string (ret);\n"
      | RBool | RErr | RFd | RInt
      | RInt64 | RCookie
-     | RUInt -> ()
+     | RUInt | REnum (_) | RFlags (_) -> ()
     );
     pr "      debug (h, \"leave: ret=\" ";
     (match ret with
-     | RBool | RErr | RFd | RInt -> pr "\"%%d\", ret"
+     | RBool | RErr | RFd | RInt | REnum (_) -> pr "\"%%d\", ret"
      | RInt64 | RCookie -> pr "\"%%\" PRIi64 \"\", ret"
      | RStaticString | RString ->
         pr "\"%%s\", ret_printable ? ret_printable : \"\""
-     | RUInt -> pr "\"%%u\", ret"
+     | RUInt | RFlags (_) -> pr "\"%%u\", ret"
     );
     pr ");\n";
     (match ret with
      | RStaticString | RString -> pr "      free (ret_printable);\n"
      | RBool | RErr | RFd | RInt
      | RInt64 | RCookie
-     | RUInt -> ()
+     | RUInt | REnum (_) | RFlags (_) -> ()
     );
     pr "    }\n";
     pr "  }\n"
@@ -824,7 +824,11 @@ let generate_docs_nbd_pod name { args; optargs; ret;
       pr "This call returns a string.  The caller must free the\n";
       pr "returned string to avoid a memory leak.\n";
    | RUInt ->
-      pr "This call returns a bitmask.\n"
+      pr "This call returns a bitmask.\n";
+   | REnum ({ enum_prefix }) ->
+      pr "This call returns one of the LIBNBD_%s_* values.\n" enum_prefix;
+   | RFlags ({ flag_prefix }) ->
+      pr "This call returns a bitmask of LIBNBD_%s_* values.\n" flag_prefix;
   );
   pr "\n";

diff --git a/generator/GoLang.ml b/generator/GoLang.ml
index 65b3690..732b81f 100644
--- a/generator/GoLang.ml
+++ b/generator/GoLang.ml
@@ -1,3 +1,4 @@
+(* hey emacs, this is OCaml code: -*- tuareg -*- *)
 (* nbd client library in userspace: generator
  * Copyright (C) 2013-2020 Red Hat Inc.
  *
@@ -95,9 +96,11 @@ let go_ret_type = function
   | RCookie -> Some "uint64"
   | RString -> Some "*string"
   (* RUInt returns (type, error) for consistency, but the error is
-   * always nil.
+   * always nil unless h is closed
    *)
   | RUInt -> Some "uint"
+  | REnum (_) -> Some "uint" (* XXX return typed constant instead? *)
+  | RFlags (_) -> Some "uint" (* XXX return typed constant instead? *)

 let go_ret_error = function
   | RErr -> None
@@ -109,6 +112,8 @@ let go_ret_error = function
   | RCookie -> Some "0"
   | RString -> Some "nil"
   | RUInt -> Some "0"
+  | REnum (_) -> Some "0"
+  | RFlags (_) -> Some "0"

 let go_ret_c_errcode = function
   | RBool -> Some "-1"
@@ -120,6 +125,8 @@ let go_ret_c_errcode = function
   | RCookie -> Some "-1"
   | RString -> Some "nil"
   | RUInt -> None
+  | REnum (_) -> None
+  | RFlags (_) -> None

 (* We need a wrapper around every function (except Close) to
  * handle errors because cgo calls are sequence points and
@@ -386,6 +393,10 @@ let print_binding (name, { args; optargs; ret; shortdesc }) =
       pr "    return &r, nil\n"
    | RUInt ->
       pr "    return uint (ret), nil\n"
+   | REnum (_) ->
+      pr "    return uint (ret), nil\n" (* XXX Proper enum type? *)
+   | RFlags (_) ->
+      pr "    return uint (ret), nil\n" (* XXX Proper bitmask type? *)
   );
   pr "}\n";
   pr "\n"
diff --git a/generator/OCaml.ml b/generator/OCaml.ml
index b45480c..4a835b0 100644
--- a/generator/OCaml.ml
+++ b/generator/OCaml.ml
@@ -66,6 +66,8 @@ and ocaml_ret_to_string = function
   | RCookie -> "cookie"
   | RString -> "string"
   | RUInt -> "int"
+  | REnum (_) -> "int" (* XXX return enum_prefix.t instead *)
+  | RFlags (_) -> "int" (* XXX return flag_prefix.t list instead *)

 and ocaml_optarg_to_string = function
   | OClosure { cbname; cbargs } ->
@@ -617,6 +619,8 @@ let print_ocaml_binding (name, { args; optargs; ret }) =
    | RBool -> pr "  rv = Val_bool (r);\n"
    | RErr -> pr "  rv = Val_unit;\n"
    | RFd | RInt | RUInt -> pr "  rv = Val_int (r);\n"
+   | REnum (_) -> pr "  rv = Val_int (r);\n" (* XXX Use Val_enum_prefix() *)
+   | RFlags (_) -> pr "  rv = Val_int (r);\n" (* XXX Use Val_flag_prefix() *)
    | RInt64 | RCookie -> pr "  rv = caml_copy_int64 (r);\n"
    | RStaticString -> pr "  rv = caml_copy_string (r);\n"
    | RString ->
diff --git a/generator/Python.ml b/generator/Python.ml
index 3fa733a..c544d10 100644
--- a/generator/Python.ml
+++ b/generator/Python.ml
@@ -521,6 +521,8 @@ let print_python_binding name { args; optargs; ret; may_set_error } =
        pr "  Py_INCREF (py_ret);\n"
     | RFd
     | RInt
+    | REnum (_)
+    | RFlags (_)
     | RUInt ->
        pr "  py_ret = PyLong_FromLong (ret);\n"
     | RInt64 | RCookie ->
-- 
2.28.0




More information about the Libguestfs mailing list