For closures with cbcount = CBOnce, FnOnce will be used instead of
FnMut. Moreover, closures in synchronous commands with
cblifetime = CBCommand will not need to live for the static lifetime.
See [
here](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) for more
information about the advantages of using `FnOnce` when possible.
---
generator/Rust.ml | 44 ++++++++++++++++++++++++++++----------------
rust/src/handle.rs | 2 ++
rust/src/types.rs | 2 ++
3 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/generator/Rust.ml b/generator/Rust.ml
index daf0e8a..052f61b 100644
--- a/generator/Rust.ml
+++ b/generator/Rust.ml
@@ -114,7 +114,7 @@ let rust_cbarg_name : cbarg -> string = function
| CBArrayAndLen (arg, _) | CBMutable arg -> rust_arg_name arg
(* Get the Rust type for an argument. *)
-let rec rust_arg_type : arg -> string = function
+let rec rust_arg_type ?(async_kind = None) : arg -> string = function
| Bool _ -> "bool"
| Int _ -> "c_int"
| UInt _ -> "c_uint"
@@ -134,15 +134,18 @@ let rec rust_arg_type : arg -> string = function
| BytesOut _ -> "&mut [u8]"
| BytesPersistIn _ -> "&'static [u8]"
| BytesPersistOut _ -> "&'static mut [u8]"
- | Closure { cbargs } -> "impl " ^ rust_closure_trait cbargs
+ | Closure { cbargs; cbcount } -> (
+ match async_kind with
+ | Some _ -> "impl " ^ rust_closure_trait cbargs cbcount
+ | None -> "impl " ^ rust_closure_trait cbargs cbcount ~lifetime:None)
(* Get the Rust closure trait for a callback, That is `Fn*(...) -> ...)`. *)
-and rust_closure_trait ?(lifetime = Some "'static") cbargs : string =
+and rust_closure_trait ?(lifetime = Some "'static") cbargs cbcount : string
=
let rust_cbargs = String.concat ", " (List.map rust_cbarg_type cbargs)
- and lifetime_constraint =
- match lifetime with None -> "" | Some x -> " + " ^ x
- in
- "FnMut(" ^ rust_cbargs ^ ") -> c_int + Send + Sync" ^
lifetime_constraint
+ and closure_type =
+ match cbcount with CBOnce -> "FnOnce" | CBMany -> "FnMut"
+ and lifetime = match lifetime with None -> "" | Some x -> " +
" ^ x in
+ sprintf "%s(%s) -> c_int + Send + Sync%s" closure_type rust_cbargs
lifetime
(* Get the Rust type for a callback argument. *)
and rust_cbarg_type : cbarg -> string = function
@@ -156,8 +159,8 @@ and rust_cbarg_type : cbarg -> string = function
| CBMutable arg -> "&mut " ^ rust_arg_type arg
(* Get the type of a rust optional argument. *)
-let rust_optarg_type : optarg -> string = function
- | OClosure x -> sprintf "Option<%s>" (rust_arg_type (Closure x))
+let rust_optarg_type ?(async_kind = None) : optarg -> string = function
+ | OClosure x -> sprintf "Option<%s>" (rust_arg_type (Closure x)
~async_kind)
| OFlags (name, flags, _) ->
sprintf "Option<%s>" (rust_arg_type (Flags (name, flags)))
@@ -422,8 +425,8 @@ let ffi_ret_to_rust call =
closure data, and a free function for the closure data. This struct is what
will be sent to a C function taking the closure as an argument. In fact,
the struct itself is generated by rust-bindgen. *)
-let print_rust_closure_to_raw_fn { cbname; cbargs } =
- let closure_trait = rust_closure_trait cbargs ~lifetime:None in
+let print_rust_closure_to_raw_fn { cbname; cbargs; cbcount } =
+ let closure_trait = rust_closure_trait cbargs cbcount ~lifetime:None in
let ffi_cbargs_names = List.flatten (List.map ffi_cbarg_names cbargs) in
let ffi_cbargs_types = List.flatten (List.map ffi_cbarg_types cbargs) in
let rust_cbargs_names = List.map rust_cbarg_name cbargs in
@@ -438,16 +441,24 @@ let print_rust_closure_to_raw_fn { cbname; cbargs } =
(List.map2 (sprintf "%s: %s") ffi_cbargs_names ffi_cbargs_types));
pr " where F: %s\n" closure_trait;
pr " {\n";
- pr " let callback_ptr = data as *mut F;\n";
- pr " let callback = &mut *callback_ptr;\n";
+ (match cbcount with
+ | CBMany ->
+ pr " let callback_ptr = data as *mut F;\n";
+ pr " let callback = &mut *callback_ptr;\n"
+ | CBOnce ->
+ pr " let callback_ptr = data as *mut Option<F>;\n";
+ pr " let callback_option: &mut Option<F> = &mut
*callback_ptr;\n";
+ pr " let callback: F = callback_option.take().unwrap();\n");
List.iter ffi_cbargs_to_rust cbargs;
pr " callback(%s)\n" (String.concat ", "
rust_cbargs_names);
pr " }\n";
- pr " let callback_data = Box::into_raw(Box::new(f));\n";
+ pr " let callback_data = Box::into_raw(Box::new(%s));\n"
+ (match cbcount with CBMany -> "f" | CBOnce -> "Some(f)");
pr " sys::nbd_%s_callback {\n" cbname;
pr " callback: Some(call_closure::<F>),\n";
pr " user_data: callback_data as *mut _,\n";
- pr " free: Some(utils::drop_data::<F>),\n";
+ pr " free: Some(utils::drop_data::<%s>),\n"
+ (match cbcount with CBMany -> "F" | CBOnce ->
"Option<F>");
pr " }\n";
pr "}\n";
pr "\n"
@@ -504,7 +515,8 @@ let print_rust_handle_method (name, call) =
let rust_args_names =
List.map rust_arg_name call.args @ List.map rust_optarg_name call.optargs
and rust_args_types =
- List.map rust_arg_type call.args @ List.map rust_optarg_type call.optargs
+ List.map (rust_arg_type ~async_kind:call.async_kind) call.args
+ @ List.map (rust_optarg_type ~async_kind:call.async_kind) call.optargs
in
let rust_args =
String.concat ", "
diff --git a/rust/src/handle.rs b/rust/src/handle.rs
index eecc593..615bbbf 100644
--- a/rust/src/handle.rs
+++ b/rust/src/handle.rs
@@ -31,6 +31,8 @@ impl Handle {
if handle.is_null() {
Err(unsafe { Error::Fatal(ErrorKind::get_error().into()) })
} else {
+ // Set a debug callback communicating with any logging
+ // implementation as defined by the log crate.
#[allow(unused_mut)]
let mut nbd = Handle { handle };
#[cfg(feature = "log")]
diff --git a/rust/src/types.rs b/rust/src/types.rs
index eb2df06..af62140 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -15,4 +15,6 @@
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+/// A cookie is a 64 bit integer returned by some aio_* methods on
+/// [crate::Handle] used to identify a running command.
pub struct Cookie(pub(crate) u64);
--
2.41.0