Skip to content

Commit 2562f48

Browse files
committed
auto merge of #9220 : kballard/rust/c_str-as_str, r=thestinger
Also rustify .as_bytes(), so it no longer calls libc::strlen() and is inlineable.
2 parents 3e1803f + 51470f3 commit 2562f48

File tree

1 file changed

+74
-3
lines changed

1 file changed

+74
-3
lines changed

src/libstd/c_str.rs

+74-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use ops::Drop;
1515
use option::{Option, Some, None};
1616
use ptr::RawPtr;
1717
use ptr;
18+
use str;
1819
use str::StrSlice;
1920
use vec::{ImmutableVector, CopyableVector};
2021
use container::Container;
@@ -97,15 +98,25 @@ impl CString {
9798
/// # Failure
9899
///
99100
/// Fails if the CString is null.
101+
#[inline]
100102
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
101-
#[fixed_stack_segment]; #[inline(never)];
102103
if self.buf.is_null() { fail!("CString is null!"); }
103104
unsafe {
104-
let len = libc::strlen(self.buf) as uint;
105+
let len = ptr::position(self.buf, |c| *c == 0);
105106
cast::transmute((self.buf, len + 1))
106107
}
107108
}
108109

110+
/// Converts the CString into a `&str` without copying.
111+
/// Returns None if the CString is not UTF-8 or is null.
112+
#[inline]
113+
pub fn as_str<'a>(&'a self) -> Option<&'a str> {
114+
if self.buf.is_null() { return None; }
115+
let buf = self.as_bytes();
116+
let buf = buf.slice_to(buf.len()-1); // chop off the trailing NUL
117+
str::from_utf8_slice_opt(buf)
118+
}
119+
109120
/// Return a CString iterator.
110121
pub fn iter<'a>(&'a self) -> CStringIterator<'a> {
111122
CStringIterator {
@@ -238,7 +249,7 @@ mod tests {
238249
use option::{Some, None};
239250

240251
#[test]
241-
fn test_to_c_str() {
252+
fn test_str_to_c_str() {
242253
do "".to_c_str().with_ref |buf| {
243254
unsafe {
244255
assert_eq!(*ptr::offset(buf, 0), 0);
@@ -257,6 +268,37 @@ mod tests {
257268
}
258269
}
259270

271+
#[test]
272+
fn test_vec_to_c_str() {
273+
let b: &[u8] = [];
274+
do b.to_c_str().with_ref |buf| {
275+
unsafe {
276+
assert_eq!(*ptr::offset(buf, 0), 0);
277+
}
278+
}
279+
280+
do bytes!("hello").to_c_str().with_ref |buf| {
281+
unsafe {
282+
assert_eq!(*ptr::offset(buf, 0), 'h' as libc::c_char);
283+
assert_eq!(*ptr::offset(buf, 1), 'e' as libc::c_char);
284+
assert_eq!(*ptr::offset(buf, 2), 'l' as libc::c_char);
285+
assert_eq!(*ptr::offset(buf, 3), 'l' as libc::c_char);
286+
assert_eq!(*ptr::offset(buf, 4), 'o' as libc::c_char);
287+
assert_eq!(*ptr::offset(buf, 5), 0);
288+
}
289+
}
290+
291+
do bytes!("foo", 0xff).to_c_str().with_ref |buf| {
292+
unsafe {
293+
assert_eq!(*ptr::offset(buf, 0), 'f' as libc::c_char);
294+
assert_eq!(*ptr::offset(buf, 1), 'o' as libc::c_char);
295+
assert_eq!(*ptr::offset(buf, 2), 'o' as libc::c_char);
296+
assert_eq!(*ptr::offset(buf, 3), 0xff);
297+
assert_eq!(*ptr::offset(buf, 4), 0);
298+
}
299+
}
300+
}
301+
260302
#[test]
261303
fn test_is_null() {
262304
let c_str = unsafe { CString::new(ptr::null(), false) };
@@ -349,4 +391,33 @@ mod tests {
349391
}
350392
}
351393
}
394+
395+
#[test]
396+
fn test_as_bytes() {
397+
let c_str = "hello".to_c_str();
398+
assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
399+
let c_str = "".to_c_str();
400+
assert_eq!(c_str.as_bytes(), bytes!(0));
401+
let c_str = bytes!("foo", 0xff).to_c_str();
402+
assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
403+
}
404+
405+
#[test]
406+
#[should_fail]
407+
fn test_as_bytes_fail() {
408+
let c_str = unsafe { CString::new(ptr::null(), false) };
409+
c_str.as_bytes();
410+
}
411+
412+
#[test]
413+
fn test_as_str() {
414+
let c_str = "hello".to_c_str();
415+
assert_eq!(c_str.as_str(), Some("hello"));
416+
let c_str = "".to_c_str();
417+
assert_eq!(c_str.as_str(), Some(""));
418+
let c_str = bytes!("foo", 0xff).to_c_str();
419+
assert_eq!(c_str.as_str(), None);
420+
let c_str = unsafe { CString::new(ptr::null(), false) };
421+
assert_eq!(c_str.as_str(), None);
422+
}
352423
}

0 commit comments

Comments
 (0)