On 7/19/2023 4:50 PM, Richard W.M. Jones wrote:
On Wed, Jul 19, 2023 at 09:09:51AM +0000, Tage Johansson wrote:
+fn test_connect_command() {
+    let nbd = libnbd::Handle::new().unwrap();
+    nbd.connect_command(&[
+        c_str!("nbdkit"),
+        c_str!("-s"),
+        c_str!("--exit-with-parent"),
+        c_str!("-v"),
+        c_str!("null"),
+    ])
+    .unwrap();
So this doesn't seem very natural Rust to me.  For example standard
library exec::execvp lets you just use:

  let err = exec::execvp("echo", &["echo", "foo"]);
  println!("Error: {}", err);

(https://docs.rs/exec/latest/exec/fn.execvp.html)

Is there a way to get rid of the c_str macro here?


Yes, there is, but it would require cloning every string. The problem is that Libnbd uses null terminated strings and Rust uses "Vector like" strings with a stored length (as C++'s `String` type). So a rust string literal (`str`) like `"nbdkit"` is stored as an array of length 6 bytes without a NULL at the end, and the integer `6` to tell the length. (See here for more explonations.) The thing is that to convert an `&str` to a null terminated string (`&CStr`) it must be cloned to make room for the extra NULL character.


One would need to use something like `impl Into<Vec<u8>>` instead of `&CStr` as type of the string arguments, and then convert it to a null terminated string with `CString::new()`.


Since these conversions would only take place when the user creates or configures the handle, the extra cost shouldn't be a problem in most cases, and I can definitely change this. But it doesn't become zero cost abstraction.


Best regards,

Tage



So to summerize: I can change the type of strings that are sent to Libnbd so that the `c_str!(...)` macro wouldn't be needed, although that would require cloning every string. But I'd rather keep the type of strings going



Rich.