about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorErick Tryzelaar <erick.tryzelaar@gmail.com>2013-08-03 17:13:14 -0700
committerErick Tryzelaar <erick.tryzelaar@gmail.com>2013-08-04 14:13:17 -0700
commit3102b1797e24b9dd8eef2f68a74ec83749d7b53d (patch)
treec68578899941c134b1bc4e59999d5a40047f89f0 /src/libstd
parent0512475fdab549182e73a42c2cd02df0cb710ebf (diff)
downloadrust-3102b1797e24b9dd8eef2f68a74ec83749d7b53d.tar.gz
rust-3102b1797e24b9dd8eef2f68a74ec83749d7b53d.zip
std: replace str::as_c_str with std::c_str
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/c_str.rs291
-rw-r--r--src/libstd/io.rs14
-rw-r--r--src/libstd/os.rs63
-rw-r--r--src/libstd/path.rs21
-rw-r--r--src/libstd/prelude.rs1
-rw-r--r--src/libstd/ptr.rs23
-rw-r--r--src/libstd/rt/borrowck.rs7
-rw-r--r--src/libstd/rt/logging.rs4
-rw-r--r--src/libstd/rt/uv/uvio.rs26
-rw-r--r--src/libstd/rt/uv/uvll.rs5
-rw-r--r--src/libstd/run.rs15
-rw-r--r--src/libstd/std.rs1
-rw-r--r--src/libstd/str.rs98
-rw-r--r--src/libstd/sys.rs10
-rw-r--r--src/libstd/unstable/dynamic_lib.rs6
-rw-r--r--src/libstd/unstable/lang.rs3
16 files changed, 403 insertions, 185 deletions
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
new file mode 100644
index 00000000000..29aa68b1533
--- /dev/null
+++ b/src/libstd/c_str.rs
@@ -0,0 +1,291 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cast;
+use iterator::Iterator;
+use libc;
+use ops::Drop;
+use option::{Option, Some, None};
+use ptr::RawPtr;
+use ptr;
+use str::StrSlice;
+use vec::ImmutableVector;
+
+/**
+ * The representation of a C String.
+ *
+ * This structure wraps a `*libc::c_char`, and will automatically free the
+ * memory it is pointing to when it goes out of scope.
+ */
+pub struct CString {
+    priv buf: *libc::c_char,
+}
+
+impl<'self> CString {
+    /**
+     * Create a C String from a str.
+     */
+    pub fn from_str(s: &str) -> CString {
+        s.to_c_str()
+    }
+
+    /**
+     * Take the wrapped `*libc::c_char` from the `CString` wrapper.
+     *
+     * # Failure
+     *
+     * If the wrapper is empty.
+     */
+    pub unsafe fn take(&mut self) -> *libc::c_char {
+        if self.buf.is_null() {
+            fail!("CString has no wrapped `*libc::c_char`");
+        }
+        let buf = self.buf;
+        self.buf = ptr::null();
+        buf
+    }
+
+    /**
+     * Puts a `*libc::c_char` into the `CString` wrapper.
+     *
+     * # Failure
+     *
+     * If the `*libc::c_char` is null.
+     * If the wrapper is not empty.
+     */
+    pub fn put_back(&mut self, buf: *libc::c_char) {
+        if buf.is_null() {
+            fail!("attempt to put a null pointer into a CString");
+        }
+        if self.buf.is_not_null() {
+            fail!("CString already wraps a `*libc::c_char`");
+        }
+        self.buf = buf;
+    }
+
+    /**
+     * Calls a closure with a reference to the underlying `*libc::c_char`.
+     */
+    pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
+        if self.buf.is_null() {
+            fail!("CString already wraps a `*libc::c_char`");
+        }
+        f(self.buf)
+    }
+
+    /**
+     * Calls a closure with a mutable reference to the underlying `*libc::c_char`.
+     */
+    pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T {
+        if self.buf.is_not_null() {
+            fail!("CString already wraps a `*libc::c_char`");
+        }
+        f(unsafe { cast::transmute(self.buf) })
+    }
+
+    /**
+     * Returns true if the CString does not wrap a `*libc::c_char`.
+     */
+    pub fn is_empty(&self) -> bool {
+        self.buf.is_null()
+    }
+
+    /**
+     * Returns true if the CString wraps a `*libc::c_char`.
+     */
+    pub fn is_not_empty(&self) -> bool {
+        self.buf.is_not_null()
+    }
+
+    /**
+     * Converts the CString into a `&[u8]` without copying.
+     */
+    pub fn as_bytes(&self) -> &'self [u8] {
+        unsafe {
+            let len = libc::strlen(self.buf) as uint;
+            cast::transmute((self.buf, len + 1))
+        }
+    }
+
+    /**
+     * Return a CString iterator.
+     */
+    fn iter(&self) -> CStringIterator<'self> {
+        CStringIterator {
+            ptr: self.buf,
+            lifetime: unsafe { cast::transmute(self.buf) },
+        }
+    }
+}
+
+impl Drop for CString {
+    fn drop(&self) {
+        if self.buf.is_not_null() {
+            unsafe {
+                libc::free(self.buf as *libc::c_void)
+            };
+        }
+    }
+}
+
+/**
+ * A generic trait for converting a value to a CString.
+ */
+pub trait ToCStr {
+    /**
+     * Create a C String.
+     */
+    fn to_c_str(&self) -> CString;
+}
+
+impl<'self> ToCStr for &'self str {
+    /**
+     * Create a C String from a `&str`.
+     */
+    fn to_c_str(&self) -> CString {
+        self.as_bytes().to_c_str()
+    }
+}
+
+impl<'self> ToCStr for &'self [u8] {
+    /**
+     * Create a C String from a `&[u8]`.
+     */
+    fn to_c_str(&self) -> CString {
+        do self.as_imm_buf |self_buf, self_len| {
+            unsafe {
+                let buf = libc::malloc(self_len as u64 + 1) as *mut u8;
+                if buf.is_null() {
+                    fail!("failed to allocate memory!");
+                }
+
+                ptr::copy_memory(buf, self_buf, self_len);
+                *ptr::mut_offset(buf, self_len as int) = 0;
+                CString { buf: buf as *libc::c_char }
+            }
+        }
+    }
+}
+
+/**
+ * External iterator for a CString's bytes.
+ *
+ * Use with the `std::iterator` module.
+ */
+pub struct CStringIterator<'self> {
+    priv ptr: *libc::c_char,
+    priv lifetime: &'self libc::c_char, // FIXME: #5922
+}
+
+impl<'self> Iterator<libc::c_char> for CStringIterator<'self> {
+    /**
+     * Advance the iterator.
+     */
+    fn next(&mut self) -> Option<libc::c_char> {
+        if self.ptr.is_null() {
+            None
+        } else {
+            let ch = unsafe { *self.ptr };
+            self.ptr = ptr::offset(self.ptr, 1);
+            Some(ch)
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use libc;
+    use ptr;
+
+    #[test]
+    fn test_to_c_str() {
+        do "".to_c_str().with_ref |buf| {
+            unsafe {
+                assert_eq!(*ptr::offset(buf, 0), 0);
+            }
+        }
+
+        do "hello".to_c_str().with_ref |buf| {
+            unsafe {
+                assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 5), 0);
+            }
+        }
+    }
+
+    #[test]
+    fn test_take() {
+        let mut c_str = "hello".to_c_str();
+        unsafe { libc::free(c_str.take() as *libc::c_void) }
+        assert!(c_str.is_empty());
+    }
+
+    #[test]
+    fn test_take_and_put_back() {
+        let mut c_str = "hello".to_c_str();
+        assert!(c_str.is_not_empty());
+
+        let buf = unsafe { c_str.take() };
+
+        assert!(c_str.is_empty());
+
+        c_str.put_back(buf);
+
+        assert!(c_str.is_not_empty());
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_take_empty_fail() {
+        let mut c_str = "hello".to_c_str();
+        unsafe {
+            libc::free(c_str.take() as *libc::c_void);
+            c_str.take();
+        }
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_put_back_null_fail() {
+        let mut c_str = "hello".to_c_str();
+        c_str.put_back(ptr::null());
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_put_back_full_fail() {
+        let mut c_str = "hello".to_c_str();
+        c_str.put_back(0xdeadbeef as *libc::c_char);
+    }
+
+    fn test_with() {
+        let c_str = "hello".to_c_str();
+        let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
+        assert!(c_str.is_not_empty());
+        assert_eq!(len, 5);
+    }
+
+    #[test]
+    #[should_fail]
+    #[ignore(cfg(windows))]
+    fn test_with_empty_fail() {
+        let mut c_str = "hello".to_c_str();
+        unsafe { libc::free(c_str.take() as *libc::c_void) }
+        c_str.with_ref(|_| ());
+    }
+}
diff --git a/src/libstd/io.rs b/src/libstd/io.rs
index 606c958b408..78c6e8d5342 100644
--- a/src/libstd/io.rs
+++ b/src/libstd/io.rs
@@ -48,6 +48,7 @@ implement `Reader` and `Writer`, where appropriate.
 
 use cast;
 use clone::Clone;
+use c_str::ToCStr;
 use container::Container;
 use int;
 use iterator::Iterator;
@@ -1040,8 +1041,8 @@ pub fn stdin() -> @Reader {
 }
 
 pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
-    let f = do path.to_str().as_c_str |pathbuf| {
-        do "r".as_c_str |modebuf| {
+    let f = do path.to_c_str().with_ref |pathbuf| {
+        do "r".to_c_str().with_ref |modebuf| {
             unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
         }
     };
@@ -1290,9 +1291,8 @@ pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
         }
     }
     let fd = unsafe {
-        do path.to_str().as_c_str |pathbuf| {
-            libc::open(pathbuf, fflags,
-                       (S_IRUSR | S_IWUSR) as c_int)
+        do path.to_c_str().with_ref |pathbuf| {
+            libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int)
         }
     };
     if fd < (0 as c_int) {
@@ -1574,8 +1574,8 @@ pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
 // FIXME: fileflags // #2004
 pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
     unsafe {
-        let f = do path.to_str().as_c_str |pathbuf| {
-            do "w".as_c_str |modebuf| {
+        let f = do path.to_c_str().with_ref |pathbuf| {
+            do "w".to_c_str().with_ref |modebuf| {
                 libc::fopen(pathbuf, modebuf)
             }
         };
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index f17a59db38f..fb4f14d33c6 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -28,6 +28,7 @@
 
 #[allow(missing_doc)];
 
+use c_str::ToCStr;
 use cast;
 use clone::Clone;
 use container::Container;
@@ -241,7 +242,9 @@ pub fn env() -> ~[(~str,~str)] {
 pub fn getenv(n: &str) -> Option<~str> {
     unsafe {
         do with_env_lock {
-            let s = n.as_c_str(|s| libc::getenv(s as *libc::c_char));
+            let s = do n.to_c_str().with_ref |buf| {
+                libc::getenv(buf)
+            };
             if ptr::null::<u8>() == cast::transmute(s) {
                 None
             } else {
@@ -274,8 +277,8 @@ pub fn getenv(n: &str) -> Option<~str> {
 pub fn setenv(n: &str, v: &str) {
     unsafe {
         do with_env_lock {
-            do n.to_str().as_c_str |nbuf| {
-                do v.to_str().as_c_str |vbuf| {
+            do n.to_c_str().with_ref |nbuf| {
+                do v.to_c_str().with_ref |vbuf| {
                     libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
                 }
             }
@@ -306,7 +309,7 @@ pub fn unsetenv(n: &str) {
     fn _unsetenv(n: &str) {
         unsafe {
             do with_env_lock {
-                do n.to_str().as_c_str |nbuf| {
+                do n.to_c_str().with_ref |nbuf| {
                     libc::funcs::posix01::unistd::unsetenv(nbuf);
                 }
             }
@@ -328,7 +331,7 @@ pub fn unsetenv(n: &str) {
 }
 
 pub fn fdopen(fd: c_int) -> *FILE {
-    do "r".as_c_str |modebuf| {
+    do "r".to_c_str().with_ref |modebuf| {
         unsafe {
             libc::fdopen(fd, modebuf)
         }
@@ -462,9 +465,9 @@ pub fn self_exe_path() -> Option<Path> {
             use libc::funcs::posix01::unistd::readlink;
 
             let mut path_str = str::with_capacity(TMPBUF_SZ);
-            let len = do path_str.as_c_str |buf| {
+            let len = do path_str.to_c_str().with_ref |buf| {
                 let buf = buf as *mut c_char;
-                do "/proc/self/exe".as_c_str |proc_self_buf| {
+                do "/proc/self/exe".to_c_str().with_ref |proc_self_buf| {
                     readlink(proc_self_buf, buf, TMPBUF_SZ as size_t)
                 }
             };
@@ -595,7 +598,7 @@ pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
 /// Indicates whether a path represents a directory
 pub fn path_is_dir(p: &Path) -> bool {
     unsafe {
-        do p.to_str().as_c_str |buf| {
+        do p.to_c_str().with_ref |buf| {
             rustrt::rust_path_is_dir(buf) != 0 as c_int
         }
     }
@@ -604,7 +607,7 @@ pub fn path_is_dir(p: &Path) -> bool {
 /// Indicates whether a path exists
 pub fn path_exists(p: &Path) -> bool {
     unsafe {
-        do p.to_str().as_c_str |buf| {
+        do p.to_c_str().with_ref |buf| {
             rustrt::rust_path_exists(buf) != 0 as c_int
         }
     }
@@ -647,7 +650,7 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
 
     #[cfg(unix)]
     fn mkdir(p: &Path, mode: c_int) -> bool {
-        do p.to_str().as_c_str |buf| {
+        do p.to_c_str().with_ref |buf| {
             unsafe {
                 libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
             }
@@ -823,7 +826,7 @@ pub fn remove_dir(p: &Path) -> bool {
 
     #[cfg(unix)]
     fn rmdir(p: &Path) -> bool {
-        do p.to_str().as_c_str |buf| {
+        do p.to_c_str().with_ref |buf| {
             unsafe {
                 libc::rmdir(buf) == (0 as c_int)
             }
@@ -848,7 +851,7 @@ pub fn change_dir(p: &Path) -> bool {
 
     #[cfg(unix)]
     fn chdir(p: &Path) -> bool {
-        do p.to_str().as_c_str |buf| {
+        do p.to_c_str().with_ref |buf| {
             unsafe {
                 libc::chdir(buf) == (0 as c_int)
             }
@@ -876,8 +879,8 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
     #[cfg(unix)]
     fn do_copy_file(from: &Path, to: &Path) -> bool {
         unsafe {
-            let istream = do from.to_str().as_c_str |fromp| {
-                do "rb".as_c_str |modebuf| {
+            let istream = do from.to_c_str().with_ref |fromp| {
+                do "rb".to_c_str().with_ref |modebuf| {
                     libc::fopen(fromp, modebuf)
                 }
             };
@@ -888,8 +891,8 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
             let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \
                                                     for source file");
 
-            let ostream = do to.to_str().as_c_str |top| {
-                do "w+b".as_c_str |modebuf| {
+            let ostream = do to.to_c_str().with_ref |top| {
+                do "w+b".to_c_str().with_ref |modebuf| {
                     libc::fopen(top, modebuf)
                 }
             };
@@ -921,7 +924,7 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
             fclose(ostream);
 
             // Give the new file the old file's permissions
-            if do to.to_str().as_c_str |to_buf| {
+            if do to.to_c_str().with_ref |to_buf| {
                 libc::chmod(to_buf, from_mode as libc::mode_t)
             } != 0 {
                 return false; // should be a condition...
@@ -948,7 +951,7 @@ pub fn remove_file(p: &Path) -> bool {
     #[cfg(unix)]
     fn unlink(p: &Path) -> bool {
         unsafe {
-            do p.to_str().as_c_str |buf| {
+            do p.to_c_str().with_ref |buf| {
                 libc::unlink(buf) == (0 as c_int)
             }
         }
@@ -1294,7 +1297,7 @@ pub fn glob(pattern: &str) -> ~[Path] {
     }
 
     let mut g = default_glob_t();
-    do pattern.as_c_str |c_pattern| {
+    do pattern.to_c_str().with_ref |c_pattern| {
         unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) }
     };
     do(|| {
@@ -1699,6 +1702,7 @@ pub mod consts {
 
 #[cfg(test)]
 mod tests {
+    use c_str::ToCStr;
     use libc::{c_int, c_void, size_t};
     use libc;
     use option::Some;
@@ -1711,7 +1715,6 @@ mod tests {
     use rand;
     use run;
     use str::StrSlice;
-    use vec::CopyableVector;
     use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
 
 
@@ -1941,19 +1944,19 @@ mod tests {
             let out = tempdir.push("out.txt");
 
             /* Write the temp input file */
-            let ostream = do input.to_str().as_c_str |fromp| {
-                do "w+b".as_c_str |modebuf| {
+            let ostream = do input.to_c_str().with_ref |fromp| {
+                do "w+b".to_c_str().with_ref |modebuf| {
                     libc::fopen(fromp, modebuf)
                 }
             };
             assert!((ostream as uint != 0u));
             let s = ~"hello";
-            let mut buf = s.to_owned().to_c_str();
-            let len = buf.len();
-            do buf.as_mut_buf |b, _len| {
-                assert_eq!(libc::fwrite(b as *c_void, 1u as size_t,
-                                        (s.len() + 1u) as size_t, ostream),
-                           len as size_t)
+            do "hello".to_c_str().with_ref |buf| {
+                let write_len = libc::fwrite(buf as *c_void,
+                                             1u as size_t,
+                                             (s.len() + 1u) as size_t,
+                                             ostream);
+                assert_eq!(write_len, (s.len() + 1) as size_t)
             }
             assert_eq!(libc::fclose(ostream), (0u as c_int));
             let in_mode = input.get_mode();
@@ -2025,11 +2028,11 @@ mod tests {
         remove_file(&path);
 
         let fd = unsafe {
-            let fd = do path.to_str().as_c_str |path| {
+            let fd = do path.to_c_str().with_ref |path| {
                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
             };
             lseek_(fd, size);
-            do "x".as_c_str |x| {
+            do "x".to_c_str().with_ref |x| {
                 assert!(write(fd, x as *c_void, 1) == 1);
             }
             fd
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 989a5cbd35b..fe8776c21d5 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -16,9 +16,11 @@ Cross-platform file path handling
 
 #[allow(missing_doc)];
 
+use c_str::ToCStr;
+use c_str;
 use clone::Clone;
-use container::Container;
 use cmp::Eq;
+use container::Container;
 use iterator::{Iterator, IteratorUtil};
 use libc;
 use option::{None, Option, Some};
@@ -341,7 +343,7 @@ mod stat {
 #[cfg(target_os = "win32")]
 impl WindowsPath {
     pub fn stat(&self) -> Option<libc::stat> {
-        do self.to_str().as_c_str |buf| {
+        do self.to_c_str().with_ref |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::stat(buf, &mut st) } {
                 0 => Some(st),
@@ -375,7 +377,7 @@ impl WindowsPath {
 #[cfg(not(target_os = "win32"))]
 impl PosixPath {
     pub fn stat(&self) -> Option<libc::stat> {
-        do self.to_str().as_c_str |buf| {
+        do self.to_c_str().with_ref |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
                 0 => Some(st),
@@ -453,7 +455,7 @@ impl PosixPath {
 #[cfg(unix)]
 impl PosixPath {
     pub fn lstat(&self) -> Option<libc::stat> {
-        do self.to_str().as_c_str |buf| {
+        do self.to_c_str().with_ref |buf| {
             let mut st = stat::arch::default_stat();
             match unsafe { libc::lstat(buf, &mut st) } {
                 0 => Some(st),
@@ -525,6 +527,12 @@ impl ToStr for PosixPath {
     }
 }
 
+impl ToCStr for PosixPath {
+    fn to_c_str(&self) -> c_str::CString {
+        self.to_str().to_c_str()
+    }
+}
+
 // FIXME (#3227): when default methods in traits are working, de-duplicate
 // PosixPath and WindowsPath, most of their methods are common.
 impl GenericPath for PosixPath {
@@ -730,6 +738,11 @@ impl ToStr for WindowsPath {
     }
 }
 
+impl c_str::ToCStr for WindowsPath {
+    fn to_c_str(&self) -> c_str::CString {
+        self.to_str().to_c_str()
+    }
+}
 
 impl GenericPath for WindowsPath {
     fn from_str(s: &str) -> WindowsPath {
diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs
index 7e21504c1d2..5b8833f3f36 100644
--- a/src/libstd/prelude.rs
+++ b/src/libstd/prelude.rs
@@ -43,6 +43,7 @@ pub use io::{print, println};
 pub use iterator::range;
 
 // Reexported types and traits
+pub use c_str::ToCStr;
 pub use clone::{Clone, DeepClone};
 pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
 pub use char::Char;
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
index 3af4769fcdb..77222490f17 100644
--- a/src/libstd/ptr.rs
+++ b/src/libstd/ptr.rs
@@ -486,24 +486,25 @@ pub mod ptr_tests {
 
     #[test]
     fn test_position() {
+        use c_str::ToCStr;
         use libc::c_char;
 
-        let s = ~"hello";
-        unsafe {
-            assert!(2u == s.as_c_str(|p| position(p, |c| *c == 'l' as c_char)));
-            assert!(4u == s.as_c_str(|p| position(p, |c| *c == 'o' as c_char)));
-            assert!(5u == s.as_c_str(|p| position(p, |c| *c == 0 as c_char)));
+        do "hello".to_c_str().with_ref |p| {
+            unsafe {
+                assert!(2u == position(p, |c| *c == 'l' as c_char));
+                assert!(4u == position(p, |c| *c == 'o' as c_char));
+                assert!(5u == position(p, |c| *c == 0 as c_char));
+            }
         }
     }
 
     #[test]
     fn test_buf_len() {
-        let s0 = ~"hello";
-        let s1 = ~"there";
-        let s2 = ~"thing";
-        do s0.as_c_str |p0| {
-            do s1.as_c_str |p1| {
-                do s2.as_c_str |p2| {
+        use c_str::ToCStr;
+
+        do "hello".to_c_str().with_ref |p0| {
+            do "there".to_c_str().with_ref |p1| {
+                do "thing".to_c_str().with_ref |p2| {
                     let v = ~[p0, p1, p2, null()];
                     do v.as_imm_buf |vp, len| {
                         assert_eq!(unsafe { buf_len(vp) }, 3u);
diff --git a/src/libstd/rt/borrowck.rs b/src/libstd/rt/borrowck.rs
index 4a6a9585b93..3a51fd032c0 100644
--- a/src/libstd/rt/borrowck.rs
+++ b/src/libstd/rt/borrowck.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use c_str::ToCStr;
 use cast::transmute;
 use libc::{c_char, c_void, size_t, STDERR_FILENO};
 use io;
@@ -76,7 +77,7 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) {
     match try_take_task_borrow_list() {
         None => { // not recording borrows
             let msg = "borrowed";
-            do msg.as_c_str |msg_p| {
+            do msg.to_c_str().with_ref |msg_p| {
                 sys::begin_unwind_(msg_p, file, line);
             }
         }
@@ -92,7 +93,7 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) {
                     sep = " and at ";
                 }
             }
-            do msg.as_c_str |msg_p| {
+            do msg.to_c_str().with_ref |msg_p| {
                 sys::begin_unwind_(msg_p, file, line)
             }
         }
@@ -231,7 +232,7 @@ pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint,
             let br = borrow_list.pop();
             if br.box != a || br.file != file || br.line != line {
                 let err = fmt!("wrong borrow found, br=%?", br);
-                do err.as_c_str |msg_p| {
+                do err.to_c_str().with_ref |msg_p| {
                     sys::begin_unwind_(msg_p, file, line)
                 }
             }
diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs
index 11d11daebc2..76619704bee 100644
--- a/src/libstd/rt/logging.rs
+++ b/src/libstd/rt/logging.rs
@@ -45,15 +45,15 @@ impl Logger for StdErrLogger {
 /// Configure logging by traversing the crate map and setting the
 /// per-module global logging flags based on the logging spec
 pub fn init(crate_map: *u8) {
+    use c_str::ToCStr;
     use os;
-    use str::StrSlice;
     use ptr;
     use option::{Some, None};
 
     let log_spec = os::getenv("RUST_LOG");
     match log_spec {
         Some(spec) => {
-            do spec.as_c_str |buf| {
+            do spec.to_c_str().with_ref |buf| {
                 unsafe { rust_update_log_settings(crate_map, buf) }
             }
         }
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index e15e3adb8c9..071a90f4a83 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -8,26 +8,26 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::*;
-use result::*;
-use ops::Drop;
-use cell::Cell;
-use cast;
+use c_str::ToCStr;
 use cast::transmute;
+use cast;
+use cell::Cell;
 use clone::Clone;
 use libc::{c_int, c_uint, c_void};
+use ops::Drop;
+use option::*;
 use ptr;
+use result::*;
 use rt::io::IoError;
 use rt::io::net::ip::{IpAddr, Ipv4, Ipv6};
-use rt::uv::*;
-use rt::uv::idle::IdleWatcher;
-use rt::uv::net::{UvIpv4, UvIpv6};
+use rt::io::{standard_error, OtherIoError};
+use rt::local::Local;
 use rt::rtio::*;
 use rt::sched::Scheduler;
-use rt::io::{standard_error, OtherIoError};
 use rt::tube::Tube;
-use rt::local::Local;
-use str::StrSlice;
+use rt::uv::*;
+use rt::uv::idle::IdleWatcher;
+use rt::uv::net::{UvIpv4, UvIpv6};
 use unstable::sync::Exclusive;
 
 #[cfg(test)] use container::Container;
@@ -663,7 +663,7 @@ impl RtioUdpSocket for UvUdpSocket {
         };
 
         let r = unsafe {
-            do ip_str.as_c_str |m_addr| {
+            do ip_str.to_c_str().with_ref |m_addr| {
                 uvll::udp_set_membership(self.native_handle(), m_addr,
                                          ptr::null(), uvll::UV_JOIN_GROUP)
             }
@@ -686,7 +686,7 @@ impl RtioUdpSocket for UvUdpSocket {
         };
 
         let r = unsafe {
-            do ip_str.as_c_str |m_addr| {
+            do ip_str.to_c_str().with_ref |m_addr| {
                 uvll::udp_set_membership(self.native_handle(), m_addr,
                                          ptr::null(), uvll::UV_LEAVE_GROUP)
             }
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index 07264839c35..bd2d28f8642 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -29,6 +29,7 @@
 
 #[allow(non_camel_case_types)]; // C types
 
+use c_str::ToCStr;
 use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
 use libc::{malloc, free};
 use libc;
@@ -372,12 +373,12 @@ pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
 }
 
 pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
-    do ip.as_c_str |ip_buf| {
+    do ip.to_c_str().with_ref |ip_buf| {
         rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
     }
 }
 pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
-    do ip.as_c_str |ip_buf| {
+    do ip.to_c_str().with_ref |ip_buf| {
         rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
     }
 }
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index 9114c4879b2..6e447d3ded4 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -12,6 +12,7 @@
 
 #[allow(missing_doc)];
 
+use c_str::ToCStr;
 use cast;
 use clone::Clone;
 use comm::{stream, SharedChan, GenericChan, GenericPort};
@@ -506,7 +507,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
 
         do with_envp(env) |envp| {
             do with_dirp(dir) |dirp| {
-                do cmd.as_c_str |cmdp| {
+                do cmd.to_c_str().with_ref |cmdp| {
                     let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
                                                  ptr::mut_null(), ptr::mut_null(), TRUE,
                                                  0, envp, dirp, &mut si, &mut pi);
@@ -697,17 +698,17 @@ fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
     // hold all the ~[u8] byte strings.
     let mut tmps = vec::with_capacity(args.len() + 1);
 
-    tmps.push(prog.to_owned().to_c_str());
+    tmps.push(prog.to_c_str());
 
     foreach arg in args.iter() {
-        tmps.push(arg.to_owned().to_c_str());
+        tmps.push(arg.to_c_str());
     }
 
     // Next, convert each of the byte strings into a pointer. This is
     // technically unsafe as the caller could leak these pointers out of our
     // scope.
     let mut ptrs = do tmps.map |tmp| {
-        tmp.as_imm_buf(|buf, _| buf as *libc::c_char)
+        tmp.with_ref(|buf| buf)
     };
 
     // Finally, make sure we add a null pointer.
@@ -734,7 +735,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
 
             // Once again, this is unsafe.
             let mut ptrs = do tmps.map |tmp| {
-                tmp.as_imm_buf(|buf, _| buf as *libc::c_char)
+                tmp.with_ref(|buf| buf)
             };
             ptrs.push(ptr::null());
 
@@ -757,7 +758,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
 
             foreach pair in env.iter() {
                 let kv = fmt!("%s=%s", pair.first(), pair.second());
-                blk.push_all(kv.to_c_str());
+                blk.push_all(kv.to_c_str().as_bytes());
             }
 
             blk.push(0);
@@ -772,7 +773,7 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
 
 fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
     match d {
-      Some(dir) => dir.to_str().as_c_str(cb),
+      Some(dir) => dir.to_c_str().with_ref(|buf| cb(buf)),
       None => cb(ptr::null())
     }
 }
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 76d65192e01..d51f0de1d27 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -172,6 +172,7 @@ pub mod local_data;
 
 pub mod gc;
 pub mod libc;
+pub mod c_str;
 pub mod os;
 pub mod path;
 pub mod rand;
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index f75bbcf20eb..851a9326392 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -1182,7 +1182,6 @@ pub trait StrSlice<'self> {
     fn subslice_offset(&self, inner: &str) -> uint;
 
     fn as_imm_buf<T>(&self, f: &fn(*u8, uint) -> T) -> T;
-    fn as_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T;
 }
 
 /// Extension methods for strings
@@ -1931,32 +1930,6 @@ impl<'self> StrSlice<'self> for &'self str {
         let v: &[u8] = unsafe { cast::transmute(*self) };
         v.as_imm_buf(f)
     }
-
-    /// Work with the byte buffer of a string as a null-terminated C string.
-    ///
-    /// Allows for unsafe manipulation of strings, which is useful for foreign
-    /// interop. This is similar to `str::as_buf`, but guarantees null-termination.
-    /// If the given slice is not already null-terminated, this function will
-    /// allocate a temporary, copy the slice, null terminate it, and pass
-    /// that instead.
-    ///
-    /// # Example
-    ///
-    /// ~~~ {.rust}
-    /// let s = "PATH".as_c_str(|path| libc::getenv(path));
-    /// ~~~
-    #[inline]
-    fn as_c_str<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
-        do self.as_imm_buf |buf, len| {
-            // NB: len includes the trailing null.
-            assert!(len > 0);
-            if unsafe { *(ptr::offset(buf, (len - 1) as int)) != 0 } {
-                self.to_owned().as_c_str(|s| f(s))
-            } else {
-                f(buf as *libc::c_char)
-            }
-        }
-    }
 }
 
 #[allow(missing_doc)]
@@ -1973,13 +1946,6 @@ pub trait OwnedStr {
     fn capacity(&self) -> uint;
     fn to_bytes_with_null(self) -> ~[u8];
 
-    /// Allocates a null terminate byte array.
-    ///
-    /// # Failure
-    ///
-    /// Fails if there are any null characters inside the byte array.
-    fn to_c_str(self) -> ~[u8];
-
     /// Work with the mutable byte buffer and length of a slice.
     ///
     /// The given length is one byte longer than the 'official' indexable
@@ -2172,13 +2138,6 @@ impl OwnedStr for ~str {
     }
 
     #[inline]
-    fn to_c_str(self) -> ~[u8] {
-        let bytes = self.to_bytes_with_null();
-        assert!(bytes.slice(0, bytes.len() - 1).iter().all(|byte| *byte != 0));
-        bytes
-    }
-
-    #[inline]
     fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
         let v: &mut ~[u8] = unsafe { cast::transmute(self) };
         v.as_mut_buf(f)
@@ -2916,63 +2875,6 @@ mod tests {
     }
 
     #[test]
-    fn test_as_c_str() {
-        let a = ~"";
-        do a.as_c_str |buf| {
-            unsafe {
-                assert_eq!(*ptr::offset(buf, 0), 0);
-            }
-        }
-
-        let a = ~"hello";
-        do a.as_c_str |buf| {
-            unsafe {
-                assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 5), 0);
-            }
-        }
-    }
-
-    #[test]
-    fn test_to_c_str() {
-        let s = ~"ศไทย中华Việt Nam";
-        let v = ~[
-            224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228,
-            184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97,
-            109, 0
-        ];
-        assert_eq!((~"").to_c_str(), ~[0]);
-        assert_eq!((~"abc").to_c_str(), ~['a' as u8, 'b' as u8, 'c' as u8, 0]);
-        assert_eq!(s.to_c_str(), v);
-    }
-
-    #[test]
-    fn test_as_c_str() {
-        let a = ~"";
-        do a.as_c_str |buf| {
-            unsafe {
-                assert_eq!(*ptr::offset(buf, 0), 0);
-            }
-        }
-
-        let a = ~"hello";
-        do a.as_c_str |buf| {
-            unsafe {
-                assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
-                assert_eq!(*ptr::offset(buf, 5), 0);
-            }
-        }
-    }
-
-    #[test]
     fn test_subslice_offset() {
         let a = "kernelsprite";
         let b = a.slice(7, a.len());
diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs
index 51609709cdb..b40f87617a9 100644
--- a/src/libstd/sys.rs
+++ b/src/libstd/sys.rs
@@ -12,13 +12,13 @@
 
 #[allow(missing_doc)];
 
+use c_str::ToCStr;
 use cast;
 use gc;
 use io;
 use libc;
 use libc::{c_char, size_t};
 use repr;
-use str::StrSlice;
 use str;
 use unstable::intrinsics;
 
@@ -115,8 +115,8 @@ pub trait FailWithCause {
 
 impl FailWithCause for ~str {
     fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
-        do cause.as_c_str |msg_buf| {
-            do file.as_c_str |file_buf| {
+        do cause.to_c_str().with_ref |msg_buf| {
+            do file.to_c_str().with_ref |file_buf| {
                 begin_unwind_(msg_buf, file_buf, line as libc::size_t)
             }
         }
@@ -125,8 +125,8 @@ impl FailWithCause for ~str {
 
 impl FailWithCause for &'static str {
     fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
-        do cause.as_c_str |msg_buf| {
-            do file.as_c_str |file_buf| {
+        do cause.to_c_str().with_ref |msg_buf| {
+            do file.to_c_str().with_ref |file_buf| {
                 begin_unwind_(msg_buf, file_buf, line as libc::size_t)
             }
         }
diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs
index 8d5654255f1..49e3e0777df 100644
--- a/src/libstd/unstable/dynamic_lib.rs
+++ b/src/libstd/unstable/dynamic_lib.rs
@@ -15,6 +15,7 @@ Dynamic library facilities.
 A simple wrapper over the platforms dynamic library facilities
 
 */
+use c_str::ToCStr;
 use cast;
 use path;
 use libc;
@@ -65,7 +66,7 @@ impl DynamicLibrary {
         // T but that feature is still unimplemented
 
         let maybe_symbol_value = do dl::check_for_errors_in {
-            do symbol.as_c_str |raw_string| {
+            do symbol.to_c_str().with_ref |raw_string| {
                 dl::symbol(self.handle, raw_string)
             }
         };
@@ -135,6 +136,7 @@ mod test {
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
 mod dl {
+    use c_str::ToCStr;
     use libc;
     use path;
     use ptr;
@@ -143,7 +145,7 @@ mod dl {
     use result::*;
 
     pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
-        do filename.to_str().as_c_str |raw_name| {
+        do filename.to_c_str().with_ref |raw_name| {
             dlopen(raw_name, Lazy as libc::c_int)
         }
     }
diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs
index e0c4950b38e..1ea815f721c 100644
--- a/src/libstd/unstable/lang.rs
+++ b/src/libstd/unstable/lang.rs
@@ -10,6 +10,7 @@
 
 //! Runtime calls emitted by the compiler.
 
+use c_str::ToCStr;
 use cast::transmute;
 use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int};
 use str;
@@ -49,7 +50,7 @@ pub fn fail_bounds_check(file: *c_char, line: size_t,
                          index: size_t, len: size_t) {
     let msg = fmt!("index out of bounds: the len is %d but the index is %d",
                     len as int, index as int);
-    do msg.as_c_str |buf| {
+    do msg.to_c_str().with_ref |buf| {
         fail_(buf, file, line);
     }
 }