c_str: add `.as_ptr` & `.as_mut_ptr` to replace `.with_[mut_]ref`.

These forms return the pointer directly, rather than the added
indirection, indentation, and inefficiencies of the closures in
`.with_ref` and `.with_mut_ref`. The two closure functions are
deprecated.

Replace

    foo(c_str.with_ref(|p| p))

    c_str.with_ref(|p| {
        foo(p);
        bar(p);
    })

with

    foo(c_str.as_ptr())

    let p = c_str.as_ptr();
    foo(p);
    bar(p);

This change does mean that one has to be careful to avoid writing `let p
= x.to_c_str().as_ptr();` since the `CString` will be freed at the end
of the statement. Previously, `with_ref` was used (and `as_ptr` avoided)
for this reason, but Rust has strongly moved away from closures to more
RAII-style code, and most uses of `.with_ref` where in the form
`.with_ref(|p| p)` anyway, that is, they were exactly `.as_ptr`.

[breaking-change]
This commit is contained in:
Huon Wilson 2014-06-14 22:46:50 +10:00
parent 6a3695d54f
commit 2c9aada10c
1 changed files with 69 additions and 0 deletions

View File

@ -133,11 +133,79 @@ impl CString {
c_str.buf
}
/// Return a pointer to the NUL-terminated string data.
///
/// `.as_ptr` returns an internal pointer into the `CString`, and
/// may be invalidated when the `CString` falls out of scope (the
/// destructor will run, freeing the allocation if there is
/// one).
///
/// ```rust
/// let foo = "some string";
///
/// // right
/// let x = foo.to_c_str();
/// let p = x.as_ptr();
///
/// // wrong (the CString will be freed, invalidating `p`)
/// let p = foo.to_c_str().as_ptr();
/// ```
///
/// # Failure
///
/// Fails if the CString is null.
///
/// # Example
///
/// ```rust
/// extern crate libc;
///
/// fn main() {
/// let c_str = "foo bar".to_c_str();
/// unsafe {
/// libc::puts(c_str.as_ptr());
/// }
/// }
/// ```
pub fn as_ptr(&self) -> *const libc::c_char {
if self.buf.is_null() { fail!("CString is null!"); }
self.buf
}
/// Return a mutable pointer to the NUL-terminated string data.
///
/// `.as_mut_ptr` returns an internal pointer into the `CString`, and
/// may be invalidated when the `CString` falls out of scope (the
/// destructor will run, freeing the allocation if there is
/// one).
///
/// ```rust
/// let foo = "some string";
///
/// // right
/// let mut x = foo.to_c_str();
/// let p = x.as_mut_ptr();
///
/// // wrong (the CString will be freed, invalidating `p`)
/// let p = foo.to_c_str().as_mut_ptr();
/// ```
///
/// # Failure
///
/// Fails if the CString is null.
pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
if self.buf.is_null() { fail!("CString is null!") }
self.buf as *mut _
}
/// Calls a closure with a reference to the underlying `*libc::c_char`.
///
/// # Failure
///
/// Fails if the CString is null.
#[deprecated="use `.as_ptr()`"]
pub fn with_ref<T>(&self, f: |*const libc::c_char| -> T) -> T {
if self.buf.is_null() { fail!("CString is null!"); }
f(self.buf)
@ -148,6 +216,7 @@ impl CString {
/// # Failure
///
/// Fails if the CString is null.
#[deprecated="use `.as_mut_ptr()`"]
pub fn with_mut_ref<T>(&mut self, f: |*mut libc::c_char| -> T) -> T {
if self.buf.is_null() { fail!("CString is null!"); }
f(self.buf as *mut libc::c_char)