@@ -436,6 +436,57 @@ impl CStr {
436
436
mem:: transmute ( slice:: from_raw_parts ( ptr, len as usize + 1 ) )
437
437
}
438
438
439
+ /// Creates a C string wrapper from a byte slice.
440
+ ///
441
+ /// This function will cast the provided `bytes` to a `CStr` wrapper after
442
+ /// ensuring that it is null terminated and does not contain any interior
443
+ /// nul bytes.
444
+ ///
445
+ /// # Examples
446
+ ///
447
+ /// ```
448
+ /// # #![feature(cstr_from_bytes)]
449
+ /// use std::ffi::CStr;
450
+ ///
451
+ /// # fn main() {
452
+ /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
453
+ /// assert!(cstr.is_some());
454
+ /// # }
455
+ /// ```
456
+ #[ unstable( feature = "cstr_from_bytes" , reason = "recently added" , issue = "31190" ) ]
457
+ pub fn from_bytes_with_nul ( bytes : & [ u8 ] ) -> Option < & CStr > {
458
+ if bytes. is_empty ( ) || memchr:: memchr ( 0 , & bytes) != Some ( bytes. len ( ) - 1 ) {
459
+ None
460
+ } else {
461
+ Some ( unsafe { Self :: from_bytes_with_nul_unchecked ( bytes) } )
462
+ }
463
+ }
464
+
465
+ /// Unsafely creates a C string wrapper from a byte slice.
466
+ ///
467
+ /// This function will cast the provided `bytes` to a `CStr` wrapper without
468
+ /// performing any sanity checks. The provided slice must be null terminated
469
+ /// and not contain any interior nul bytes.
470
+ ///
471
+ /// # Examples
472
+ ///
473
+ /// ```
474
+ /// # #![feature(cstr_from_bytes)]
475
+ /// use std::ffi::{CStr, CString};
476
+ ///
477
+ /// # fn main() {
478
+ /// unsafe {
479
+ /// let cstring = CString::new("hello").unwrap();
480
+ /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
481
+ /// assert_eq!(cstr, &*cstring);
482
+ /// }
483
+ /// # }
484
+ /// ```
485
+ #[ unstable( feature = "cstr_from_bytes" , reason = "recently added" , issue = "31190" ) ]
486
+ pub unsafe fn from_bytes_with_nul_unchecked ( bytes : & [ u8 ] ) -> & CStr {
487
+ mem:: transmute ( bytes)
488
+ }
489
+
439
490
/// Returns the inner pointer to this C string.
440
491
///
441
492
/// The returned pointer will be valid for as long as `self` is and points
@@ -670,4 +721,31 @@ mod tests {
670
721
671
722
assert_eq ! ( cstr_hash, cstring_hash) ;
672
723
}
724
+
725
+ #[ test]
726
+ fn from_bytes_with_nul ( ) {
727
+ let data = b"123\0 " ;
728
+ let cstr = CStr :: from_bytes_with_nul ( data) ;
729
+ assert_eq ! ( cstr. map( CStr :: to_bytes) , Some ( & b"123" [ ..] ) ) ;
730
+ assert_eq ! ( cstr. map( CStr :: to_bytes_with_nul) , Some ( & b"123\0 " [ ..] ) ) ;
731
+
732
+ unsafe {
733
+ let cstr_unchecked = CStr :: from_bytes_with_nul_unchecked ( data) ;
734
+ assert_eq ! ( cstr, Some ( cstr_unchecked) ) ;
735
+ }
736
+ }
737
+
738
+ #[ test]
739
+ fn from_bytes_with_nul_unterminated ( ) {
740
+ let data = b"123" ;
741
+ let cstr = CStr :: from_bytes_with_nul ( data) ;
742
+ assert ! ( cstr. is_none( ) ) ;
743
+ }
744
+
745
+ #[ test]
746
+ fn from_bytes_with_nul_interior ( ) {
747
+ let data = b"1\0 23\0 " ;
748
+ let cstr = CStr :: from_bytes_with_nul ( data) ;
749
+ assert ! ( cstr. is_none( ) ) ;
750
+ }
673
751
}
0 commit comments