How to cast String to u_char

I am new to Rust FFI, please consider the following types and struct:

pub type __u_char = ::std::os::raw::c_uchar;
pub type u_char = __u_char;

pub struct ngx_str_t {
    pub len: usize,
    pub data: *mut u_char,
}

How can I create an ngx_str_t instance from String type?

I used the following solution:

let cstring = CString::new("my string").unwrap();
let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()) };
let ptr = cstr.as_ptr();

let inst = ngx_str_t {
    len: "my string".len(),
    data: ptr as (*mut u_char),
};

Can I trust the result?

If you pass the string as a pointer and length, I don't think you need CString at all. You can just pass rust_string.as_ptr() as *mut u_char.
You just need to make sure that the other end is ok with UTF-8 encoded data.

2 Likes

You need to at least forget the original (C)String, otherwise the data the pointer points to gets deallocated as soon as the scope ends.
You also need to ensure that the string is not deallocated on the nginx-side, but instead is passed back into your Rust code for deallocation.

3 Likes

CString::into_raw is more explicit than as_ptr + mem::forget when you want the receiving code to take ownership of the buffer.

The String equivalent is .into_boxed_str().into_raw(), which also releases any excess capacity. You must do this if you want the receiving code to eventually destroy the buffer, unless you keep track of the capacity in some other way.

1 Like

If you want the receiving code to destroy the buffer you must also be overriding the global allocator so that it's using the same allocator in both places, if you are doing that then having some excess capacity doesn't matter as the allocator is tracking that data per allocation anyway.

Not necessarily, you can just pass it back to a function written in Rust to be reconstituted into a Box and dropped.

This is true for malloc/free, but not true of allocators in general.

Oh, you were referring to some other Rust code receiving it back from the FFI code. Yes, in that case you do need to pass the capacity as well (which is easiest by making it equal to the length). I misunderstood what you meant by "receiving code".

1 Like