[FFI] How can I borrow a mutable raw pointer in a function?

Hello,

I have a function on a ffi linked list and want to modify it in a function (append()). However, the compiler complains that is not mutable. How can I mutate this my variable?

#[repr(C)]
  pub struct CChemSCs {
       pub chemsc: *const ChemSC,
       pub next: *mut CChemSCs,
  }
// ...
unsafe {
        let mut results = CChemSCs {
              chemsc: std::ptr::null_mut(),
              next: std::ptr::null_mut(),
          };
  
          if chemscs.len() > 0 {
              results.chemsc = &chemscs[0];
              results.next = std::ptr::null_mut();
          }
  
          if chemscs.len() > 1 {
              for i in 1..chemscs.len() as usize {
                  // here I call for append()
                  append(&mut results, chemscs[i].clone());
              }
          }
          return Box::into_raw(Box::new(results));
   }

// the function append works on raw pointers
unsafe fn append(chemscs: *mut CChemSCs, chemsc: ChemSC) {
    loop {
        if (*chemscs).next.is_null() {
            let cc = CChemSCs {
                chemsc: &chemsc,
                next: std::ptr::null_mut(),
            };
            (*chemscs).next = Box::into_raw(Box::new(cc));
        } else {
            chemscs = (*chemscs).next;
        }
    }
}

Compiler error:

   Compiling chemsc_cffi v0.1.0 (file:///home/herzog/Lipotype/ltx2/backend/chemsc_cffi)
src/lib.rs:172:13: 172:38 error: re-assignment of immutable variable `chemscs` [E0384]
src/lib.rs:172             chemscs = (*chemscs).next;
                           ^~~~~~~~~~~~~~~~~~~~~~~~~
src/lib.rs:172:13: 172:38 help: run `rustc --explain E0384` to see a detailed explanation
src/lib.rs:163:18: 163:25 note: prior assignment occurs here
src/lib.rs:163 unsafe fn append(chemscs: *mut CChemSCs, chemsc: ChemSC) {

The parameter chemscs needs to be declared mutable too if you want to reassign it, like:

unsafe fn append(mut chemscs: *mut CChemSCs, chemsc: ChemSC)
1 Like

Thx! It did not appear to me to add a mut in front of the variable name. I think this is a bit too flexible and introduces redundancy. But anyway, it did it for me.

The two muts mean different things. The one you already had let you change the struct that the pointer is pointing to. The one you added lets you change which struct the pointer points to.

Note that making an owned function parameter mut does the exact same thing as starting your function with let mut param = param;. It doesn't matter at all to the caller.

3 Likes

I just wanted to drop a note to let you know this thread saved me a lot of hair-pulling! Thank you!