Description
It's currently non-trivial to do a &[&str]
-> **c_char
conversion correctly; I think there should be a function in std::c_str
that handles this (as well as optionally null terminating the **c_char
).
v
is a &[&str]
, f
is a function taking a **c_char
. I've put the types of intermediates for clarity.
Incorrect
a
v.as_imm_buf(|buf: *&str, _| f(buf as **c_char))
The *&str
→ **c_char
cast is wrong.
b
let ptrs: ~[*c_char] = v.map(|s: & &str| s.with_c_str(|cstr: *c_char| cstr));
ptrs.as_imm_buf(|buf: **c_char, _| f(buf))
The *c_char
from with_c_str
shouldn't leave the closure, since it with_c_str
allocates an internal buffer. (This is a general problem with methods that pass a raw pointer to a closure: it is extremely easy and tempting to just return that pointer immediately and thus (possibly) create a dangling reference.)
Correct
(at least, I think it is correct)
let c_strs: ~[CString] = v.map(|s: & &str| s.to_c_str());
let mut ptrs: ~[*c_char] = c_strs.map(|c: &CString| c.with_ref(|ptr| ptr));
if null_terminate {
ptrs.push(std::ptr::null());
}
ptrs.as_imm_buf(|buf: **c_char, _| f(buf))
The c_strs
vector must live at least as at least as long as the **c_char
is used. In this (unusual) case, returning the *c_char
from with_ref
is ok (if c_strs
is kept alive long enough).