Rust FFI: Sending strings to the outside world
thefullsnack.com
thefullsnack.com
BTW...I'm a big fan of Neon and have even sent in a PR for an issue I found. I've used it to write Google Cloud Functions without having to write a single line of JavaScript and it's been pretty easy to work with. Rust is the perfect language for Cloud Functions/Lambda since those services are billed per CPU time/memory and Rust has very little overhead in those regards. Writing services that use the minimum allowed resources makes using these serverless platforms very price competitive with running your own servers, even when you reach a pretty considerable load. I do find the current direction Neon is headed (using macros to essentially write JavaScript code in Rust) to be not particularly useful (I'd rather my Rust code look like Rust), but the project is already at a point where I can build around it, so I'm not complaining.
Anyways, your comment seemed to imply that ffi was part of the Node platform and that it wasn't appropriate for production, and I disagree with both of those. Ffi is just a different approach that's suitable for different situations.
#[no_mangle]
pub extern fn string_array() -> *const *const u8 {
let v = vec![
"Hello\0".as_ptr(),
"World\0".as_ptr()
];
v.as_ptr()
}
This has exactly the same problem as with `CString`; the `Vec` is deallocated at function exit. [ '��\u0002\u0002', '8+���~', buffer: <Buffer > ]
I will update the post. Thanks for pointing it out! :D... guess it doesn't?
#[no_mangle]
pub extern fn free_string(p: *mut c_char) {
unsafe {
let _ = CString::from_raw(p);
// optionally you could explicitly call drop, but
// that is unnecessary, since it is automatically dropped
// at end of scope
}
}
Also the `into_raw` method on CString gives you a pointer while simultaneously taking ownership of the CString, so mem::forget isn't necessary if you use `into_raw` rather than `as_ptr`.> Then we use std::mem::forget to release it from the responsibility of Rust.
CString::into_raw does that whole song and dance for you.
For Vectors you probably want to convert them to boxed slices first, at which point you can use Box::into_raw (to get the slice's head pointer).
For this and many other reasons (mainly pushing the onus of managing memory onto the developer instead of automating it) I can't really get behind Rust. I think many other languages like Swift are also barking up the wrong tree by being too pedantic.
Of course, the fairly explicit nature of Rust is annoying/inappropriate for some tasks which don't need quite that level of control, but I think you're missing the power Rust brings to concurrency. (Of course, whether this particular article uses that power is a different question.)
I can't read the article on my phone because too much code is cut off (and the right margin is unpleasantly close to the main text, unlike the left margin).