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 <
https://doc.rust-lang.org/reference/type-layout.html> 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()`
<
https://doc.rust-lang.org/std/ffi/struct.CString.html#method.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.