Reputation: 113
I am trying to save a String in Wasm heap as Uint8Array
after encoding and saving the pointer to the string and the length in a Struct so that i can access the string later. Below is My code in rust
#[wasm_bindgen]
pub struct CustomString{
ptr : *const u8,
len: usize
}
#[wasm_bindgen]
impl CustomString{
pub fn create(len:usize) -> Self{
let mut d = Vec::with_capacity(len);
log!("{}",len);
CustomString{
ptr: d.as_ptr(),
len
}
}
pub fn as_ptr(&self) -> *const u8{
self.ptr
}
pub fn print_string(&self){
let js = unsafe { std::slice::from_raw_parts(self.ptr, self.len) };
let js = unsafe { std::str::from_utf8_unchecked(js) };
log!("{}",js)
}
}
My JS side code is as follows :
function myTest (){
debugger;
const { memory } = wasm;
let encoder = new TextEncoder();
let mystring = "Ujjal";
let encodedString = encoder.encode(mystring);
let length = encodedString.length;
console.log(length)
let cs = CustomString.create(length);
let ptr = cs.as_ptr();
const asBytes = new Uint8Array(memory.buffer, ptr, length);
asBytes.set(encodedString);
return cs;
}
let cs = myTest();
function decode(cs){
cs.print_string();
}
decode(cs);
Ideally it should print the given string but it shows some unrelated junk value. Couldn't figure what is going wrong as I am pretty new to rust and wasm.
This is the console message I am getting when i run this and sometime Memory error.
Upvotes: 0
Views: 9315
Reputation: 113
So finally I could figure it out. Below is my solution.
Rust Code:
pub struct CustomString{
ptr : *mut u8,
len: usize
}
#[wasm_bindgen]
impl CustomString{
pub fn create(len:usize) -> Self{
let mut d = String::with_capacity(len);
// log!("{}",len);
let ptr = d.as_mut_ptr();
std::mem::forget(d);
CustomString{
ptr,
len
}
}
pub fn as_ptr(&self) -> *mut u8{
self.ptr
}
pub fn as_string(&self)-> String{
let m = unsafe { String::from_raw_parts(self.ptr, self.len, self.len) };
m
}
pub fn print_string(&self){
let m = unsafe { String::from_raw_parts(self.ptr, self.len, self.len) };
log!("{}",m)
}
}
JS Code :
function myCS(string){
const { memory } = wasm;
let encoder = new TextEncoder();
let encodedString = encoder.encode(string);
let length = encodedString.length;
let cs = CustomString.create(length);
let ptr = cs.as_ptr();
const asBytes = new Uint8Array(memory.buffer, ptr, length);
asBytes.set(encodedString);
return cs;
}
One problem with this solution is that it is not very performant. I tested it with 500000 random length strings
. It takes about 4000+ ms
.
Is there a better way to do this keeping performance in mind.
Upvotes: 0
Reputation: 198
In create
you are creating vec d
and taking its pointer, but after function ends vec d
is freed and your pointer points to invalid memory.
Upvotes: 3