rusterlium / erlang_nif-sys

Low level bindings to Erlang NIF API for Rust
Apache License 2.0
90 stars 19 forks source link

ErlNifBinary.data should be *mut u8 instead of *const u8 (?) #8

Closed tatsuya6502 closed 8 years ago

tatsuya6502 commented 8 years ago

I am trying to port vinoski/bitwise NIF examples to Rust, but I found that Rust compiler does not let me update the contents of the data field of ErlNifBinary.

I am not totally sure as I just started to play with Rust a few days ago, but it looks like the data field should be defined as *mut u8 instead of *const u8?

ruster_unsafe/src/lib.rs

pub struct ErlNifBinary {
    pub size: size_t,
    pub data: *const u8,
    bin_term: ERL_NIF_TERM,
    ref_bin: *mut c_void,
}

Here is relevant code from my program. (Ported from bitwise_nif.c#L14-L38)

/// Erlang: -spec exor(binary(), byte::0..255) -> binary().
///
/// exor misbehaves on a regular scheduler thread when the incomng binary is
/// large because it blocks the thread for too long. But it works fine on a
/// dirty scheduler.
extern "C" fn exor(env: *mut ErlNifEnv,
                   argc: c_int,
                   args: *const ERL_NIF_TERM) -> ERL_NIF_TERM {
    unsafe {
        let mut bin: ErlNifBinary = uninitialized();
        let mut outbin: ErlNifBinary = uninitialized();
        let mut val: c_uint = uninitialized();

        if argc != 2
            || 0 == enif_inspect_binary(env, *args, &mut bin)
            || 0 == enif_get_uint(env, *args.offset(1), &mut val)
            || val > 255 {
            return enif_make_badarg(env);
        }
        if bin.size == 0 {
            return *args;
        }
        enif_alloc_binary(bin.size, &mut outbin);
        do_xor(bin.data, bin.size, outbin.data, val as u8);  // <-- This line does not compile.

        // @TODO: Implement enif_make_tuple2() and friends in ruster_unsafe
        // enif_make_tuple2(env,
        //                  enif_make_binary(env, &mut outbin),
        //                  enif_make_int(env, 0))
        enif_make_binary(env, &mut outbin)
    }
}

fn do_xor(bin_data: *const u8, length: usize, outbin_data: *mut u8, byte: u8) {
    let bin_slice: &[u8] = unsafe {slice::from_raw_parts(bin_data, length)};
    let outbin_slice: &mut[u8] = unsafe {slice::from_raw_parts_mut(outbin_data, length)};

    for (b, ob) in bin_slice.iter().zip(outbin_slice.iter_mut()) {
        (*ob) = (*b) ^ byte;
    }
}

And the compile error:

src/lib.rs:75:36: 75:47 error: mismatched types:
 expected `*mut u8`,
    found `*const u8`
(values differ in mutability) [E0308]
src/lib.rs:75         do_xor(bin.data, bin.size, outbin.data, val as u8);
                                                 ^~~~~~~~~~~
src/lib.rs:75:36: 75:47 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `bitwise_rust_erlang`.

If I change the data field to *mut u8, it will compile.

% cargo build --release
   Compiling libc v0.2.4
   Compiling ruster_unsafe v0.2.0 (https://github.com/tatsuya6502/ruster_unsafe/?rev=nif-2.9#2f68285f)
   Compiling bitwise_rust_erlang v0.1.0 (file:///usr/home/tatsuya/workhub/dev/bitwise-rust-erlang)
% ls -lh target/release/lib*.so
-rwxr-xr-x  1 tatsuya  tatsuya   2.0M Jan  7 21:36 target/release/libbitwise_nif.so
tatsuya6502 commented 8 years ago

Forgot to mention about the versions:

goertzenator commented 8 years ago

I agree with you. Can you submit your change as a PR?

tatsuya6502 commented 8 years ago

Thank you for the prompt reply! I submitted the PR https://github.com/goertzenator/ruster_unsafe/pull/9.

goertzenator commented 8 years ago

And thank you for the PR. Also, I'm pleased to see that this works on FreeBSD.