Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I index C arrays in Rust?

Tags:

arrays

rust

ffi

I have a C function returning a pointer:

type MYSQL_RES_REF = *mut c_void;
type MYSQL_ROW = *const *const c_char;

#[no_mangle]
extern "C" {
    fn mysql_fetch_row(res: MYSQL_RES_REF) -> MYSQL_ROW;
}

let pointer = mysql_fetch_row(self.res);
let row_p = match pointer {
    p if p == (0 as *const *const c_char) => panic!(),
    p => p,
};

let field: &[u8] = unsafe { ffi::c_str_to_bytes(row_p[i]) };

but attempting to index it (the last line) results in an error:

error: cannot index a value of type `*const *const i8`

I wonder if std::c_vec was what I wanted, but apparently that has been removed.

like image 512
dhardy Avatar asked Jan 20 '15 16:01

dhardy


People also ask

How do you declare an array in Rust?

In Rust, arrays are created using square brackets [] and their size needs to be known at compile time. An array whose size is not defined is called a slice.

Is Rust 0 indexed?

Just as with methods, Rust will also insert dereference operations on a repeatedly to find an implementation. Indices are zero-based for arrays and slices.

How do you append to an array in Rust?

There is no way to do this in stable Rust; arrays cannot have values added or removed at runtime; their lengths are fixed at compile time.

Do arrays implement copy Rust?

Arrays of any size implement the following traits if the element type allows it: Copy. Clone. Debug.


2 Answers

There is an offset method on pointers which can be used as:

let new_p = p.offset(i);

to get a pointer i elements away from the current one. It is not bounds-checked, obviously, so you must ensure it stays within the bounds (or one-past-the-end).


There is also an unstable offset intrinsic.

like image 116
Matthieu M. Avatar answered Nov 08 '22 00:11

Matthieu M.


If you have the length of your C array, you can convert the pointer and the length into a Rust slice and then use all the existing support for slices:

use libc::size_t; // 0.2.51
use std::slice;

/// Our opaque C type
#[repr(C)]
struct MyCType {
    private: [u8; 0],
}

extern "C" {
    fn get_ptr_and_len(len: *mut size_t) -> *const MyCType;
    fn do_something_with_type(v: *const MyCType);
}

fn ptr_and_len() {
    unsafe {
        let mut len = 0;
        let ptr = get_ptr_and_len(&mut len);

        let slice = slice::from_raw_parts(ptr, len);

        // Indexing
        do_something_with_type(&slice[42]);

        // Iteration
        for v in slice {
            do_something_with_type(v);
        }
    }
}

See also:

  • What's the Rust idiom to define a field pointing to a C opaque pointer?
  • How do I initialize an opaque C struct when using Rust FFI?
like image 32
Shepmaster Avatar answered Nov 08 '22 00:11

Shepmaster