-1

I have this code in C that writes in a fd the command. My issue is that I can't represent the same behaviour in Rust language because apparently the .write() doesn't takes the same parameters as C's write(). The function is the following:

static void set_address(int32_t fd, uint64_t start_address, uint64_t len){
    uint64_t command[3];
    int64_t bytes;

    command[0] = SET_ADDRESS_AREA;
    command[1] = start_address;
    command[2] = len;

    bytes = write(fd, command, (ssize_t)LEN_SET_ADDRESS_AREA);

    if (bytes != LEN_SET_ADDRESS_AREA)
    {
        printf("\nError\n");
        exit(-1);
    }
}

So my code is:

for (i,val) in ref_memory.iter().enumerate().step_by(DIM_SLICE){ 
                let mut start_address = val ; 
                
                let p = std::ptr::addr_of!(start_address);
                println!("the address index of val is {:?}",p);
                let mut command = (SET_ADDRESS_AREA,start_address,DIM_SLICE);
               
                let file_buffer = File::create(_path);
                let bytes_written = file_buffer.unwrap().write(command);
                }
             }

Writing this

let bytes_written = file_buffer.unwrap().write(command);

I get the error:

Mismatched types: expected reference &[u8] and found tuple (u8, &u8, u8)

Should I create a struct to pass just one reference of type &u8?

Alternatively, is there a crate that offers this feature?

CLetter
  • 1
  • 2

2 Answers2

1

Its not clear why you're diverged so much from the C code when converting it to Rust. Why the for loop? Why the addr_of? Why create the file in the function when the original clearly already has the file descriptor? Why create a tuple instead of an array?

The direct conversion is mostly straight-forward.

fn set_address(file: &mut File, start_address: u64, len: u64) {
    let command: [u64; 3] = [
        SET_ADDRESS_AREA,
        start_address,
        len
    ];

    let bytes = file.write(bytemuck::cast_slice(&command)).unwrap();

    if bytes != LEN_SET_ADDRESS_AREA {
        println!("Error");
        std::process::exit(-1);
    }
}

The only tricky part here is my use of the bytemuck crate to convert a [u64] into a [u8]. You can do without it, but is a bit more annoying.

Here is a full example on the playground that includes the above and two other methods.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • IMHO using an external crate is a little bit more annoying than using `core::mem::transmute` – Miiao Dec 11 '22 at 00:56
  • @Miiao I would not typically suggest using `unsafe` to a Rust newcomer, *especially* not `transmute` which is incredibly easy to get wrong. – kmdreko Dec 11 '22 at 01:14
  • I create a Tuple because start_address is a type: &u8 differently from the others (u8). – CLetter Dec 11 '22 at 10:16
0

Should I create a struct to pass just one reference of type &u8?

You don't need to create anything. write(2) takes 3 parameters because it needs an fd, a pointer to a buffer to write, and an amount of data to write.

In Rust, the fd is the object on which the method is called (file_buffer), and a slice (&[u8]) has a length so it provides both the "data to write" buffer and the amount of data to write.

What you should do is either just write ref_memory directly (it's not clear why you even split it across multiple writes, especially since you write them all to the same file anyway), or use chunks to split the input buffer into sub-slices, that you can then write directly

let p = std::ptr::addr_of!(start_address);

That makes absolutely no sense. That's a raw pointer to the start_address local variable, which is a copy of val.

Your C code is also... not right. Partial writes are perfectly valid and legal, there's lots of reasons why they might happen (e.g. hardware drivers, network buffer sizes, ...), a write(2) error is signalled by a return value of -1. Following which you'd generally read errno or use perror(3) or strerror(3) to report why the call failed.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • i don't want writing the memory with the same file. The idea behind is to scroll down the memory in slice of 4kb and in each slice write the command. – CLetter Dec 11 '22 at 10:19