I'm writing a c-binding to a Rust function. The Rust function takes a 3D slice where 2 dimensions are of size two. Essentially it's a slice of 2D line segments where a line segment is represented by 2 points.
This means the segments have type:
segments: [[[f32; 2]; 2]]
Now since I call this from C I only have a simple f32 pointer at the FFI boundary. My multi-dimensional array from c is in row-major memory order which I understand matches what Rust would expect. So morally I should be able to say to rust: It's just that type.
I have looked at https://doc.rust-lang.org/std/ptr/fn.slice_from_raw_parts.html but I don't see how I can handle a more complex structure with that.
So to make it very concrete I want to be able to call foo from foo_c and foo should handle the conversion from pointer to the 3D slice/array structure.
#[no_mangle]
pub unsafe extern fn foo_c(segments: *f32, n_segments: usize) {
foo(...)
}
fn foo(segments: [[[f32; 2]; 2]]) {
...
}
If possible I would like to do this without copying any data around.
Any help is appreciated!
First I think you made some typos, so I'm assuming your code is:
#[no_mangle]
// missing `const`
pub unsafe extern fn foo_c(segments: *const f32, n_segments: usize) {
foo(...)
}
// missing `&`
fn foo(segments: &[[[f32; 2]; 2]]) {
...
}
The solution is:
#[no_mangle]
pub unsafe extern fn foo_c(segments: *const f32,n_segments: usize) {
// first we cast the pointer to get the slice `T`
// so from a generic `*const f32` to `*const T` where T is `[[f32; 2]; 2]`
let ptr = segments as *const [[f32; 2]; 2];
// we construct the slice using `slice_from_raw_parts`
// after we got the correct pointer.
let segments_slice = std::ptr::slice_from_raw_parts::<[[f32;2];2]>(ptr,n_segments);
// we still have `*const [[f32; 2]; 2]` which we need to convert
// to `&[[f32; 2]; 2]` so we use `&*` (dereference then borrow).
foo(&*segments_slice)
}
fn foo(segments: &[[[f32; 2]; 2]]) {
println!("segments {:?}",segments);
}
Related
How can I convert a mutable u8 pointer to a mutable reference of another type?
let ptr: *mut u8;
let reference: &mut SomeType = ?; // What should i do here?
I have found a sort-of viable solution, but I wonder if there is a better way:
let reference = unsafe { &mut *(ptr as *mut SomeType) };
You have already found an acceptable method. A slightly preferable one is to use pointer::cast instead of as, because that explicitly specifies that you are trying to change the type of the referent and not any of the many other things as can do.
let ptr = ptr.cast::<SomeType>();
let reference = unsafe { &mut *ptr };
Do not use std::mem::transmute for this. Transmuting should always be the last resort in any circumstance (the nomicon and function documentation say so!), because it reinterprets the bytes regardless of what they are — in this case it'll convert any pointer-sized value, such as a reference to the pointer. By sticking with cast and &*, we catch more possible type errors. (Clippy even has a default lint against using transmute here.)
You could use std::mem::transmute instead:
use std::mem::transmute;
#[repr(transparent)]
struct SomeStruct(u8);
fn main() {
let a = &mut 10u8;
let ptr = a as *mut u8;
let reference: &mut SomeStruct = unsafe { transmute(ptr) };
}
I'm admittedly new to Rust. That being said, this doesn't make sense to me yet finding out why the behavior I'm seeing isn't what I expect seems like a good learning opportunity:
use std::iter::Enumerate;
use std::collections::HashMap;
impl Solution {
pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
let mut numToI: HashMap<i32, usize> = HashMap::new();
for (i,v) in nums.iter().enumerate() {
let num: i32 = *v;
let complement: i32 = target - num;
if numToI.contains_key(complement) {
return vec![i as i32, numToI.get(complement) as i32];
} else {
numToI.insert(complement, i);
}
}
return vec![-1,-1];
}
}
Here I'm doing the simple question twoSum. I understand that nums.iter().enumerate() will return the values i and v, which are of type usize and a pointer to the element in nums (so in this case a reference to an i32), respectively. The thing I'm having trouble with is that although I specify numToI is a HashMap<i32, usize>, not HashMap<&i32, usize>, and I dereference to get the value of v with *v and assign the value to num, when I check if the HashMap numToI contains this i32 dereferenced value as a key, I get the error: expected &i32, found i32 on the call to contains_key. Why is this? Is it because the HashMap type always requires a pointer rather than a raw value, or is it due to an intricacy of Rust I'm not aware of? Shouldn't it expect a pointer for the key instead of a i32 if I had used HashMap<&i32, i32>?
More importantly, if this is due to a difference between Rust and C that has to do with the way borrowing etc. is used in Rust, where can I learn more about the intricacies of these differences?
contains_key takes a reference. It doesn't need to take ownership of the value to test with - it just needs to look at it temporarily.
Rust is complaining that you are passing in an i32 by value instead of a reference to it. It should tell you to borrow instead: numToI.contains_key(&complement).
That's the only issue with your code, really. HashMap keys don't need to be references, and it would be really inconvenient if they did.
To dereference a raw pointer, we must use unsafe code. What are the situations in which raw pointers can be used (and can be useful) in ways that don't involve using unsafe code at all?
Pretty much the only thing you can do is cast the raw pointer to an usize. You can use that to do stuff like getting the index in an array from a reference into the array.
fn get_index_in_array(array: &[i32], item: &i32) -> usize {
let array_ptr: *const i32 = array.as_ptr();
let item_ptr: *const i32 = item;
let distance = ((item_ptr as usize) - (array_ptr as usize)) / std::mem::size_of::<i32>();
assert!(distance < array.len());
distance
}
fn main() {
let arr = [1, 2, 3, 4];
println!("{}", get_index_in_array(&arr, &arr[2]));
}
2
I want to create a Vec<T> and make some room for it, but I don't know how to do it, and, to my surprise, there is almost nothing in the official documentation about this basic type.
let mut v: Vec<i32> = Vec<i32>(SIZE); // How do I do this ?
for i in 0..SIZE {
v[i] = i;
}
I know I can create an empty Vec<T> and fill it with pushes, but I don't want to do that since I don't always know, when writing a value at index i, if a value was already inserted there yet. I don't want to write, for obvious performance reasons, something like :
if i >= len(v) {
v.push(x);
} else {
v[i] = x;
}
And, of course, I can't use the vec! syntax either.
While vec![elem; count] from the accepted answer is sufficient to create a vector with all elements equal to the same value, there are other convenience functions.
Vec::with_capacity() creates a vector with the given capacity but with zero length. It means that until this capacity is reached, push() calls won't reallocate the vector, making push() essentially free:
fn main() {
let mut v = Vec::with_capacity(10);
for i in 0..10 {
v.push(i);
}
println!("{:?}", v);
}
You can also easily collect() a vector from an iterator. Example:
fn main() {
let v: Vec<_> = (1..10).collect();
println!("{:?}", v);
}
And finally, sometimes your vector contains values of primitive type and is supposed to be used as a buffer (e.g. in network communication). In this case you can use Vec::with_capacity() + set_len() unsafe method:
fn main() {
let mut v = Vec::with_capacity(10);
unsafe { v.set_len(10); }
for i in 0..10 {
v[i] = i;
}
println!("{:?}", v);
}
Note that you have to be extra careful if your vector contains values with destructors or references - it's easy to get a destructor run over a uninitialized piece of memory or to get an invalid reference this way. It will also work right if you only use initialized part of the vector (you have to track it yourself now). To read about all the possible dangers of uninitialized memory, you can read the documentation of mem::uninitialized().
You can use the first syntax of the vec! macro, specifically vec![elem; count]. For example:
vec![1; 10]
will create a Vec<_> containing 10 1s (the type _ will be determined later or default to i32). The elem given to the macro must implement Clone. The count can be a variable, too.
There is the Vec::resize method:
fn resize(&mut self, new_len: usize, value: T)
This code resizes an empty vector to 1024 elements by filling with the value 7:
let mut vec: Vec<i32> = Vec::new();
vec.resize(1024, 7);
Editor's note: This question predates Rust 1.0 and syntax and methods have changed since then. Some answers account for Rust 1.0.
I have a function which I would like to have modify a vector in place.
fn f(v: &mut Vec<int>) {
v = Vec::from_elem(10 as uint, 0i);
}
fn main() {
let mut v: Vec<int> = Vec::new();
f(&mut v);
}
But this fails to compile. Specifically, I would like to resize v to contain 10 elements of value zero. What am I doing wrong?
Use the clear and resize methods. (This seems to be the right answer as of Rust 1.0 and 1.5, respectively.)
fn f(v: &mut Vec<u32>) {
// Remove all values in the vector
v.clear();
// Fill the vector with 10 zeros
v.resize(10, 0);
}
fn main() {
let mut v: Vec<u32> = Vec::new();
f(&mut v);
assert!(v == [0,0,0,0,0,0,0,0,0,0]);
}
Editor's note: This answer predates Rust 1.0 and is no longer necessarily accurate. Other answers still contain valuable information.
You're looking for the grow method.
let mut vec = vec![1i,2,3];
vec.grow(4, &10);
println!("{}", vec);
Or a combination of grow and clear.
You can browse the docs here: http://static.rust-lang.org/doc/master/std/vec/struct.Vec.html