Working with my code I came across something that is bothering me. I have a null-terminated string stored in a fixed-length array, [i8; 255], but the function that converts it to a string only accepts &[u8].
I saw that there is a way in CString to use a Vec to convert but the function is still unstable and requires a Vec, if possible I wanted to do this without resorting to such complexity.
The problem is that no matter what conversion I do I can't convert a sized array to an unsized array and I haven't found anything on the internet about it.
Is there a way Rust allows the function to accept my buffer?
I’m not entirely sure what you mean by “unsized array”, but if you want to call the from_bytes_with_nul function, just pass it a reference to your fixed-length array. Rust can automatically (and implicitly) convert a &[u8; 255] to a &[u8]. The type [u8] (or the type &[u8], depending on who you ask) is called a slice.
Simply passing a reference did not solve the problem. "unsized" was precisely the term used by the compiler when pointing out the error.
But I will try your approach here.
Hmm, in case you’re trying to understand and/or resolve a particular compiler error it might help if you shared the error message.
Regarding the term “unsized” Rust has so-called “unsized types” (or “dynamically sized types”, DSTs) of which the slice type [u8] (or more generally [T]) is an example. At a first approximation, such types don’t exist at all but are just a trick to use the &-symbol in things like slice types like &[u8] or trait object types such as e.g. &dyn Any. More precisely, unsized types can only exist behind a reference, which includes &, but also &mut, Box<> or Arc<> for example. Something like Box<dyn Error> is a common example using a different pointer type (in this case Box), but Box<[u8]> is also possible.
In the case of a slice &[u8], the reference-type &[u8] consists of a pointer to some data which can belong for example to an array as in your case, or to a Vec, etc, plus—additionally—the length of the slice. So &[u8] internally is like a pair (*const u8, usize) of a pointer and a length. This makes the &[u8] references twice as large as ordinary references; for this reason these are also called “fat pointers”. Then there are coercions in place that can create slices like &[u8] from other reference types such as &[u8; 42] or &Vec<u8>. These coercions are build-in for arrays, or reslized through the Deref trait and based on unsafe API such as slice::from_raw_parts, like is the case for Vec.
Oh, and by the way, the term “array” in Rust always refers to types [T; N] of known, fixed length.
Sorry for the vague initial post.
I never got along very well with slices and this is draining my energy.
I'll correct myself here, I mixed the terms of Rust and C.
The problem is:
The C buffer is of the char type, in Rust it was represented as i8 but the function uses u8.
error[E0308]: mismatched types
--> tests/vulkan_loader.rs:19:57
|
19 | let s = std::ffi::CStr::from_bytes_with_nul(&layer.layerName).unwrap().to_str().unwrap();
| ^^^^^^^^^^^^^^^^ expected slice `[u8]`, found array `[i8; 256]`
|
= note: expected reference `&[u8]`
found reference `&[i8; 256]`
If I try to convert to & [u8] I can't, it's a conversion that doesn't involve primitive types.
error[E0605]: non-primitive cast: `&[i8; 256]` as `&[u8]`
--> tests/vulkan_loader.rs:19:57
|
19 | let s = std::ffi::CStr::from_bytes_with_nul(&layer.layerName as &[u8]).unwrap().to_str().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
What I would like to know is how to make the function accept the buffer returned to me in the safest way possible.
On a second thought, it looks like you’re trying to get a str out of this in the end anyways. Which sounds like the [i8; 256] buffer might not actually be a string of length 255 but potentially shorter (with a 0 byte in the middle). CStr::from_bytes_with_nul will actually panic in this case. If this is the case, let’s hope that the code that got you the [i8; 256] in the first place is sound in that that array doesn’t actually contain any uninitialized data. Assuming it is sound, you would still need to split at the first 0 byte manually (unless there’s a nice crate or function that can help us that I don’t know of). Given that it’s i8s, does the string actually contain any non-ASCII characters and/or do you need to validate that? Anyways, you can build str from u8 of ASCII (or more generally Utf8-encoded) slices directly without using CStr. For searching the u8 byte, the bstr crate might be useful. Here’s a version that does not check for non-ASCII characters and supports ASCII or Utf8 even if the latter is weird with signed i8s: Rust Playground.