Skip to content

Commit

Permalink
c_str: add .as_ptr & .as_mut_ptr to replace .with_[mut_]ref.
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
huonw committed Jun 29, 2014
1 parent 6a3695d commit 2c9aada
Showing 1 changed file with 69 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/librustrt/c_str.rs
Expand Up @@ -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)
Expand All @@ -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)
Expand Down

0 comments on commit 2c9aada

Please sign in to comment.