@@ -15,6 +15,7 @@ use ops::Drop;
1515use option:: { Option , Some , None } ;
1616use ptr:: RawPtr ;
1717use ptr;
18+ use str;
1819use str:: StrSlice ;
1920use vec:: { ImmutableVector , CopyableVector } ;
2021use 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