about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2013-09-15 20:30:03 -0700
committerKevin Ballard <kevin@sb.org>2013-09-15 20:30:03 -0700
commit51470f3b97428756bee70e564db026ba2e2bceb6 (patch)
treeb16a3549799bce4e36b257601a1481c6e49c6540
parent72f62abebfe5819de1762f5b91b237cc93a6b78c (diff)
downloadrust-51470f3b97428756bee70e564db026ba2e2bceb6.tar.gz
rust-51470f3b97428756bee70e564db026ba2e2bceb6.zip
c_str: Add new method .as_str() -> Option<&str>
Also rustify .as_bytes(), so it no longer calls libc::strlen() and is
inlineable.
-rw-r--r--src/libstd/c_str.rs77
1 files changed, 74 insertions, 3 deletions
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index 51b70a07be8..a2842efbf8a 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -15,6 +15,7 @@ use ops::Drop;
 use option::{Option, Some, None};
 use ptr::RawPtr;
 use ptr;
+use str;
 use str::StrSlice;
 use vec::{ImmutableVector, CopyableVector};
 use container::Container;
@@ -97,15 +98,25 @@ impl CString {
     /// # Failure
     ///
     /// Fails if the CString is null.
+    #[inline]
     pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
-        #[fixed_stack_segment]; #[inline(never)];
         if self.buf.is_null() { fail!("CString is null!"); }
         unsafe {
-            let len = libc::strlen(self.buf) as uint;
+            let len = ptr::position(self.buf, |c| *c == 0);
             cast::transmute((self.buf, len + 1))
         }
     }
 
+    /// Converts the CString into a `&str` without copying.
+    /// Returns None if the CString is not UTF-8 or is null.
+    #[inline]
+    pub fn as_str<'a>(&'a self) -> Option<&'a str> {
+        if self.buf.is_null() { return None; }
+        let buf = self.as_bytes();
+        let buf = buf.slice_to(buf.len()-1); // chop off the trailing NUL
+        str::from_utf8_slice_opt(buf)
+    }
+
     /// Return a CString iterator.
     pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
         CStringIterator {
@@ -238,7 +249,7 @@ mod tests {
     use option::{Some, None};
 
     #[test]
-    fn test_to_c_str() {
+    fn test_str_to_c_str() {
         do "".to_c_str().with_ref |buf| {
             unsafe {
                 assert_eq!(*ptr::offset(buf, 0), 0);
@@ -258,6 +269,37 @@ mod tests {
     }
 
     #[test]
+    fn test_vec_to_c_str() {
+        let b: &[u8] = [];
+        do b.to_c_str().with_ref |buf| {
+            unsafe {
+                assert_eq!(*ptr::offset(buf, 0), 0);
+            }
+        }
+
+        do bytes!("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);
+            }
+        }
+
+        do bytes!("foo", 0xff).to_c_str().with_ref |buf| {
+            unsafe {
+                assert_eq!(*ptr::offset(buf, 0), 'f' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 1), 'o' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 2), 'o' as libc::c_char);
+                assert_eq!(*ptr::offset(buf, 3), 0xff);
+                assert_eq!(*ptr::offset(buf, 4), 0);
+            }
+        }
+    }
+
+    #[test]
     fn test_is_null() {
         let c_str = unsafe { CString::new(ptr::null(), false) };
         assert!(c_str.is_null());
@@ -349,4 +391,33 @@ mod tests {
             }
         }
     }
+
+    #[test]
+    fn test_as_bytes() {
+        let c_str = "hello".to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
+        let c_str = "".to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!(0));
+        let c_str = bytes!("foo", 0xff).to_c_str();
+        assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_as_bytes_fail() {
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        c_str.as_bytes();
+    }
+
+    #[test]
+    fn test_as_str() {
+        let c_str = "hello".to_c_str();
+        assert_eq!(c_str.as_str(), Some("hello"));
+        let c_str = "".to_c_str();
+        assert_eq!(c_str.as_str(), Some(""));
+        let c_str = bytes!("foo", 0xff).to_c_str();
+        assert_eq!(c_str.as_str(), None);
+        let c_str = unsafe { CString::new(ptr::null(), false) };
+        assert_eq!(c_str.as_str(), None);
+    }
 }