How do I get a *mut c_char from a Str? - rust

To be able to use C library, I need to give a *mut c_char parameter to a function. But I don't find a way to have it from a str.
I converted my str to a CString, that's ok, but there's no more way from CString to get a *mut c_char in the nightly build. I found that in 0.12.0 there was a method, but now, what is the process to get that *mut c_char?

let bytes = String::from_str("Test").into_bytes() + b"\0";
let cchars = bytes.map_in_place(|b| b as c_char);
let name: *mut c_char = cchars.as_mut_ptr();
The basic idea is the same as yours but there is no need to slice the Vec explicitly; also a zero byte is appended to the buffer. See also my comment to the question.

Five years later and none of these solutions are working (for me, at least).
A slightly modified version of this answer:
let string: &str = "Hello, world!";
let bytes: Vec<u8> = String::from(string).into_bytes();
let mut c_chars: Vec<i8> = bytes.iter().map(| c | *c as i8).collect::<Vec<i8>>();
c_chars.push(0); // null terminator
let ptr: *mut c_char = c_chars.as_mut_ptr();

Look at this piece of documentation, the fn as_mut_ptr() has been moved to the slice part of the API. So you need a mutable slice of type &mut [c_char]. And AFAIK you cannot get that from a CString, those would be read-only.
Instead you can use a mut Vec<c_char>:
let mut x : Vec<c_char> = ...;
let slice = x.as_mut_slice();
let ptr = slice.as_mut_ptr();

Now (2022), into_raw() works well for me, for example:
use std::ffi::CString;
use std::os::raw::c_char;
fn main() {
let c_string = CString::new("Hello!").expect("CString::new failed");
let raw: *mut c_char = c_string.into_raw();
}
Check https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_raw for more information.

Thanks to rodrigo's post, I found a way (very dirty, but it works) to solve my problem. Here is the code :
let mut string = std::string::String::from_str("Test");
let bytes = string.into_bytes();
let mut cchar : Vec<c_char> = bytes.map_in_place(|w| w as c_char);
let slice = cchar.as_mut_slice();
let name: *mut c_char = slice.as_mut_ptr();
A bit complex in my opinion

If you want to
let mut hello = b"Hello World\0".to_vec().as_mut_ptr() as *mut i8;

Related

How do I print u64 to a buffer on stack in Rust

I'm trying to format an u64 to a &str, but without dynamically allocating any memory on heap. I want to manually declare a space on stack (e.g., let mut buffer = [0u8; 20] and print the u64 to buffer and get a &str from it with some unsafe.
I tryied write!(&mut buffer[..], "{}", i), but it returns a Result<()> and I couldn't get the length of the formatted string so as to unsafely convert it to &str.
I'm currently straightly coping the implementation of Display for u64 from std library, is there a better way of doing so?
You could use a Cursor:
use std::io::{Write, Cursor};
fn main() {
let mut cursor = Cursor::new([0u8; 20]);
let i = 42u64;
write!(cursor, "{i}").unwrap();
let pos = cursor.position();
let buffer = cursor.into_inner();
let text = std::str::from_utf8(&buffer[..pos as usize]).unwrap();
println!("{text}");
}

How to write a slice into a file?

I have code which interracts with C via bindings. In it I have this:
let a1: *const i8 = get_data();
let size1 = get_size_of_data();
let a2 = ::std::slice::from_raw_parts(a2, size1);
I need to write data to which a1 points. Or a2 as a slice. The size or length of the data is known.
I tried:
let mut f1 = File::create("my_file.dat").unwrap();
// ??? f1.write_all(a2).expect("unable to write binary data to file");
// ??? f1.write_all(a2.as_bytes).expect("unable to write binary data to file");
and nothing has compiled.
How to do it?
You need pass a &[u8] to write_all, but you have a &[i8]. So, the only change you need is to cast your *const i8 to a *const u8 in slice::from_raw_parts
let a1: *const i8 = std::ptr::null(); // replace with `get_data()`
let size1 = 42; // replace `get_size_of_data()`
let a2: &[u8] = unsafe { std::slice::from_raw_parts(a1 as *const u8, size1) };
use std::io::Write;
let mut f1 = std::fs::File::create("my_file.dat").unwrap();
f1.write_all(a2).expect("write must succeed");

Convert Vec<[f64;1]> to Vec<f64>

I am new to rust and I am playing with it. When I was following some tutorial, I found a vector of type <[f64,1]>. I thought it should be simple to transform it to [f64] but could not find a simple way other than for loop. Is there other way?
let y: Vec<[f64;1]> = [[1],[2],[3],[4]];
let mut y2: Vec<f64> = Vec::new();
for each in &y {
y2.push(each[0]);
}
y in your example is not a Vec; you probably forgot vec! in front.
Furthermore, floats should be 1.0 not 1.
I don't know why you find this for loop not simple, but if you want other ways:
Using iterator pattern
let y: Vec<[f64; 1]> = vec![[1.0], [2.0], [3.0], [4.0]];
let y2: Vec<f64> = y.iter().map(|&[f]| f).collect();
Using unsafe
Since [f64; 1] and f64 are equal-sized (both 8 bytes),
we can transmute the Vec directly:
let y: Vec<[f64; 1]> = vec![[1.0], [2.0], [3.0], [4.0]];
let y2 = unsafe {
// Ensure the original vector is not dropped.
let mut y = std::mem::ManuallyDrop::new(y);
Vec::from_raw_parts(y.as_mut_ptr() as *mut f64,
y.len(),
y.capacity())
};
This is more complex, but it will reuse the same memory without copying.
you could use the flatten() method:
let y_vec: Vec<f64> = y.iter().flatten().cloned().collect();

Read an arbitrary number of bytes from type implementing Read

I have something that is Read; currently it's a File. I want to read a number of bytes from it that is only known at runtime (length prefix in a binary data structure).
So I tried this:
let mut vec = Vec::with_capacity(length);
let count = file.read(vec.as_mut_slice()).unwrap();
but count is zero because vec.as_mut_slice().len() is zero as well.
[0u8;length] of course doesn't work because the size must be known at compile time.
I wanted to do
let mut vec = Vec::with_capacity(length);
let count = file.take(length).read_to_end(vec).unwrap();
but take's receiver parameter is a T and I only have &mut T (and I'm not really sure why it's needed anyway).
I guess I can replace File with BufReader and dance around with fill_buf and consume which sounds complicated enough but I still wonder: Have I overlooked something?
Like the Iterator adaptors, the IO adaptors take self by value to be as efficient as possible. Also like the Iterator adaptors, a mutable reference to a Read is also a Read.
To solve your problem, you just need Read::by_ref:
use std::io::Read;
use std::fs::File;
fn main() {
let mut file = File::open("/etc/hosts").unwrap();
let length = 5;
let mut vec = Vec::with_capacity(length);
file.by_ref().take(length as u64).read_to_end(&mut vec).unwrap();
let mut the_rest = Vec::new();
file.read_to_end(&mut the_rest).unwrap();
}
1. Fill-this-vector version
Your first solution is close to work. You identified the problem but did not try to solve it! The problem is that whatever the capacity of the vector, it is still empty (vec.len() == 0). Instead, you could actually fill it with empty elements, such as:
let mut vec = vec![0u8; length];
The following full code works:
#![feature(convert)] // needed for `as_mut_slice()` as of 2015-07-19
use std::fs::File;
use std::io::Read;
fn main() {
let mut file = File::open("/usr/share/dict/words").unwrap();
let length: usize = 100;
let mut vec = vec![0u8; length];
let count = file.read(vec.as_mut_slice()).unwrap();
println!("read {} bytes.", count);
println!("vec = {:?}", vec);
}
Of course, you still have to check whether count == length, and read more data into the buffer if that's not the case.
2. Iterator version
Your second solution is better because you won't have to check how many bytes have been read, and you won't have to re-read in case count != length. You need to use the bytes() function on the Read trait (implemented by File). This transform the file into a stream (i.e an iterator). Because errors can still happen, you don't get an Iterator<Item=u8> but an Iterator<Item=Result<u8, R::Err>>. Hence you need to deal with failures explicitly within the iterator. We're going to use unwrap() here for simplicity:
use std::fs::File;
use std::io::Read;
fn main() {
let file = File::open("/usr/share/dict/words").unwrap();
let length: usize = 100;
let vec: Vec<u8> = file
.bytes()
.take(length)
.map(|r: Result<u8, _>| r.unwrap()) // or deal explicitly with failure!
.collect();
println!("vec = {:?}", vec);
}
You can always use a bit of unsafe to create a vector of uninitialized memory. It is perfectly safe to do with primitive types:
let mut v: Vec<u8> = Vec::with_capacity(length);
unsafe { v.set_len(length); }
let count = file.read(vec.as_mut_slice()).unwrap();
This way, vec.len() will be set to its capacity, and all bytes in it will be uninitialized (likely zeros, but possibly some garbage). This way you can avoid zeroing the memory, which is pretty safe for primitive types.
Note that read() method on Read is not guaranteed to fill the whole slice. It is possible for it to return with number of bytes less than the slice length. There are several RFCs on adding methods to fill this gap, for example, this one.

How should I call Vec::with_capacity with an i32?

I have a function which allocates a vector on the stack. This code doesn't work:
fn my_func(n: i32) {
let mut v = Vec::with_capacity(n);
}
The compiler says n needs to be a usize. I suppose that makes sense from a type safety point of view, but I need to use n in other calculations where an i32 is called for. What's the proper way to handle this?
Cast to usize.
let n: i32 = 4;
let v = Vec::<i16>::with_capacity(n as usize);

Resources