This code shows FFI from Rust to Fortran because it's where I noticed the issue, but I'm pretty sure this is not Fortran specific and maybe even FFI-independent.
I have src/main.rs, a rather minimal thing:
extern crate libc;
extern "C" {
static mut __wrapper_mod_MOD_a_string: [libc::c_char; 30];
fn __wrapper_mod_MOD_say_hi();
}
fn main() {
let s = String::from("hello");
unsafe { __wrapper_mod_MOD_say_hi() };
for i in unsafe { __wrapper_mod_MOD_a_string.iter_mut() } {
*i = ' ' as libc::c_char;
}
for (i, c) in unsafe { __wrapper_mod_MOD_a_string }.iter_mut().zip(s.chars()) {
*i = c as libc::c_char;
}
unsafe { __wrapper_mod_MOD_say_hi() };
for (i, c) in unsafe { __wrapper_mod_MOD_a_string.iter_mut().zip(s.chars()) } {
*i = c as libc::c_char;
}
unsafe { __wrapper_mod_MOD_say_hi() };
}
This calls into src/wrapper.f90:
module wrapper_mod
implicit none
private
public :: say_hi
character(30) :: a_string
contains
subroutine say_hi
if (trim(a_string) == 'hello') then
write(6,*) 'Howdy there, partner'
else
write(6,*) 'Rude of you not to greet me'
endif
end subroutine say_hi
end module wrapper_mod
I get the output:
Rude of you not to greet me
Rude of you not to greet me
Howdy there, partner
Why? The only difference in the last two lines is the scoping of the unsafe
block. I thought the unsafe action is the access over FFI, but once I have an array, it should be "safe" to iterate it as I please. Clearly I've misunderstood something.
My Cargo.toml has cc = "1.0"
in [build-dependencies]
and I have the following build.rs:
extern crate cc;
fn main() {
cc::Build::new()
.file("src/wrapper.f90")
.compile("libwrapper.a");
println!("cargo:rustc-link-lib=static=wrapper");
println!("cargo:rustc-link-lib=dylib=gfortran");
}
There's nothing particular about the use of unsafe
here. The same thing happens with regular curly braces:
fn main() {
let mut bytes = [0; 4];
let new_bytes = b"demo";
for (i, &c) in { bytes }.iter_mut().zip(new_bytes) {
*i = c;
}
println!("{:?}", bytes);
// [0, 0, 0, 0]
for (i, &c) in { bytes.iter_mut().zip(new_bytes) } {
*i = c;
}
println!("{:?}", bytes);
// [100, 101, 109, 111]
}
Usage of the curly braces forces a move of the variables inside the braces. Since [libc::c_char; 30]
and [u8; 4]
both implement Copy
, an implicit copy is made due to move. You can take a mutable reference and move that through the curly braces:
for (i, &c) in { &mut bytes }.iter_mut().zip(new_bytes) {
*i = c;
}
See also: