I'm writing Rust code for WebAssembly to handle strings from JavaScript land.
Since WebAssembly has no real string type, I'm trying to pass a pointer to WebAssembly memory object which points to UTF-8 encoded string.
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &[u8] = std::slice::from_raw_parts(ptr, length as usize);
// do some operations on buf
0
}
}
It works fine, expect that I have to depend on the std
crate, which bloats the final binary to about 600KB.
Is there any way to get rid of std::slice::from_raw_parts
but still be able to cast a raw pointer to a slice?
You cannot cast a raw pointer to a slice because in Rust, a slice is not a mere pointer, it is a pointer and a size (otherwise it could not be safe).
If you do not want to use std
, you can use the core
crate:
extern crate core;
#[no_mangle]
pub extern "C" fn check(ptr: *mut u8, length: u32) -> u32 {
unsafe {
let buf: &mut [u8] = core::slice::from_raw_parts_mut(ptr, length as usize);
}
// do some operations on buf
0
}
The core
crate is the part of the std
crate suitable for embedded, i.e. without all the stuff that needs some allocation.
It is possible to manually construct something similar to a slice, which is a fat pointer that consists of a thin pointer and a length. Then cast a pointer-to-this-construct to a pointer-to-slice.
This approach is not only unsafe, it also relies on Rust internals (memory layout of a slice) that are not guaranteed to remain stable between compiler version, or even systems I suppose. @Boiethios' answer is the way to go if you want to be sure that your code works correctly in the future. However, for educational purposes, the code below may still be interesting:
unsafe fn make_slice<'a>(ptr: *const u8, len: usize) -> &'a [u8] {
// place pointer address and length in contiguous memory
let x: [usize; 2] = [ptr as usize, len];
// cast pointer to array as pointer to slice
let slice_ptr = &x as * const _ as *const &[u8];
// dereference pointer to slice, so we get a slice
*slice_ptr
}
fn main() {
let src: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let raw_ptr = &src[1] as *const u8;
unsafe {
println!("{:?}", make_slice(raw_ptr, 3)); // [2, 3, 4]
}
}
(tested on playground with Rust Stable 1.26.2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With