Dummy line required in my code!

I've the below code, that works fine ONLY if I added the dummy line:

    let x = format!("{:?}", to);   
    // or
   // println!("{:?}", to);

Without it the call of let recipient = match ... is returning Error!!

use wasm_bindgen::prelude::*;
use std::os::raw::{c_char};
use std::ffi::{CString, CStr};

#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
pub fn hi(to :&str) -> String {
    let returned = rust_greeting(to.as_ptr() as *const c_char);

    let c_str = unsafe { CStr::from_ptr(returned) };
    let recipient = match c_str.to_str()  {
        Err(_) => "Error",
        Ok(string) => string,
    };

    recipient.to_string()
}

// Main function in the module, that will be called in the 3 platforms
#[cfg_attr(not(target_arch = "wasm32"), no_mangle)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
pub extern fn rust_greeting(to: *const c_char) -> *mut c_char {
    let x = format!("{:?}", to);   // <= This dummy line is required?!
    // or
   // println!("{:?}", to);
    let c_str = unsafe { CStr::from_ptr(to) };
    let recipient = match c_str.to_str() {
        Err(_) => "Error",
        Ok(string) => string,
    };
    CString::new("Hello ".to_owned() + recipient).unwrap().into_raw()
}

You can't pass str::as_ptr() to a function expecting a *const c_char - the latter expects a null-terminated C string, whereas the former produces just a pointer to the data (Rust's string slices don't carry a null-terminator). To get a c_char from a &str, you'll need to copy it into a CString, which adds the null-terminator.

2 Likes

Thanks a lot, below fixed it:

    // copy the &str into CSring 
    let c_str = CString::new(to).unwrap();
    // cast the CString into c_char
    let c_world: *const c_char = c_str.as_ptr() as *const c_char;

BTW, let c_world = c_str.as_ptr() as *const _ works too if the type is known from context. That comes handy when C code keeps mixing up whether it wants signed or unsigned char.