How to convert a non-zero-terminated C string to Rust &str or String

How can I convert a non-zero-terminated C string to Rust &str or String?
I have head: *libc::c_char and size: usize of a non-zero-terminated string.

I think I could malloc a buffer, copy from *libc::c_char to the buffer, then

str::from_utf8(CStr::from_ptr(buf).to_bytes()).unwrap()

Is there a better way?

CStr works with zero-terminated strings, and since you said your string isn't zero-terminated, that means CStr is the wrong thing to use.
Instead just do:
std::str::from_utf8(std::slice::from_raw_parts(head, size)).unwrap()

3 Likes

(Assuming it's UTF-8 encoded, of course... :P)

It works great.
Thanks!

Note: this will create an str with an unbound lifetime. Be very careful.

1 Like

Thanks for the head-up.
After all, I came to use the following code to create a String out of &str.

std::str::from_utf8(std::slice::from_raw_parts(head, size)).unwrap().to_string()

You may want to use .to_owned() method instead of .to_string() to avoid calling heavy weight formatting machinery.

2 Likes

Stupid question: why does to_string call heavy formatting machinery?

1 Like

Because to_string() is a method of ToString trait, which has impl<T: Display> ToString for T, and as Rust doesn't support impl specialization now, there's no way to override this impl for more specific case of &str. And as the only thing the impl<T: Display> ToString for T knows about T is it implements Display, it can use Display::fmt() method only to build string from T, which uses, well, heavy weight formatting machinery.

Maybe in the future Rust, when will get implementations specialization, this impl will be overriden for &str and you won't have to worry about it any more, but for now there's str::to_owned() method, created just because of this problem.

1 Like

We already have an RFC for specialization open

1 Like

That's great! It's not in stable yet, though.

Makes sense, thanks.