@@ -436,6 +436,57 @@ impl CStr {
436436 mem:: transmute ( slice:: from_raw_parts ( ptr, len as usize + 1 ) )
437437 }
438438
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+
439490 /// Returns the inner pointer to this C string.
440491 ///
441492 /// The returned pointer will be valid for as long as `self` is and points
@@ -670,4 +721,31 @@ mod tests {
670721
671722 assert_eq ! ( cstr_hash, cstring_hash) ;
672723 }
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+ }
673751}
0 commit comments