As far as I was able to determine, it's currently *impossible* to allocate a C NUL-terminated string in Rust and then return it to C (transferring ownership), without leaking memory. There is support for passing the string to C (borrowing).
To complicate matters, it's not possible for the C code to just call `free` on the allocated string, due to the different allocators in use.
`CString` has no way to recreate itself from a pointer. This commit adds one. This is complicated a bit because Rust `Vec`s want the pointer, size, and capacity.
To deal with that, another method to shrink and "leak" the `CString` to a `char *` is also provided.
We can then use `strlen` to determine the length of the string, which must match the capacity.
**TODO**
- [x] Improve documentation
- [x] Add stability markers
- [x] Convert to `Box<[u8]>`
### Example code
With this example code:
```rust
#![feature(libc)]
#![feature(cstr_to_str)]
#![feature(c_str_memory)]
extern crate libc;
use std::ffi::{CStr,CString};
#[no_mangle]
pub extern fn reverse(s: *const libc::c_char) -> *const libc::c_char {
let s = unsafe { CStr::from_ptr(s) };
let s2 = s.to_str().unwrap();
let s3: String = s2.chars().rev().collect();
let s4 = CString::new(s3).unwrap();
s4.into_ptr()
}
#[no_mangle]
pub extern fn cleanup(s: *const libc::c_char) {
unsafe { CString::from_ptr(s) };
}
```
Compiled using `rustc --crate-type dylib str.rs`, I was able to link against it from C (`gcc -L. -l str str.c -o str`):
```c
#include <stdio.h>
extern char *reverse(char *);
extern void cleanup(char *);
int main() {
char *s = reverse("Hello, world!");
printf("%s\n", s);
cleanup(s);
}
```
As well as dynamically link via Ruby:
```ruby
require 'fiddle'
require 'fiddle/import'
module LibSum
extend Fiddle::Importer
dlload './libstr.dylib'
extern 'char* reverse(char *)'
extern 'void cleanup(char *)'
end
s = LibSum.reverse("hello, world!")
puts s
LibSum.cleanup(s)
```
Doc patch for #26120. Extra words here, because "value" is repeated.
I haven't read about whether/how it should go to stable (sorry), but I think it would help newcomers.
Thanks,
The text claimed 'any borrow must last for a _smaller_ scope than the
owner', however the accurate way of describing the comparison is
inclusive (i.e., 'less than or equal to' vs. 'less than').
* Add “complex” mappings to `char::to_lowercase` and `char::to_uppercase`, making them yield sometimes more than on `char`: #25800. `str::to_lowercase` and `str::to_uppercase` are affected as well.
* Add `char::to_titlecase`, since it’s the same algorithm (just different data). However this does **not** add `str::to_titlecase`, as that would require UAX#29 Unicode Text Segmentation which we decided not to include in of `std`: https://github.com/rust-lang/rfcs/pull/1054 I made `char::to_titlecase` immediately `#[stable]`, since it’s so similar to `char::to_uppercase` that’s already stable. Let me know if it should be `#[unstable]` for a while.
* Add a special case for upper-case Sigma in word-final position in `str::to_lowercase`: #26035. This is the only language-independent conditional mapping currently in `SpecialCasing.txt`.
* Stabilize `str::to_lowercase` and `str::to_uppercase`. The `&self -> String` on `str` signature seems straightforward enough, and the only relevant issue I’ve found is #24536 about naming. But `char` already has stable methods with the same name, and deprecating them for a rename doesn’t seem worth it.
r? @alexcrichton