@@ -234,15 +234,18 @@ pub struct NulError(usize, Vec<u8>);
234234
235235/// An error indicating that a nul byte was not in the expected position.
236236///
237- /// The slice used to create a [`CStr`] must have one and only one nul
238- /// byte at the end of the slice .
237+ /// The slice used to create a [`CStr`] or the vector used to create a
238+ /// [`CString`] must have one and only one nul byte, positioned at the end .
239239///
240240/// This error is created by the
241241/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
242- /// [`CStr`]. See its documentation for more.
242+ /// [`CStr`] or the [`from_vec_with_nul`][`CString::from_vec_with_nul`] method
243+ /// on [`CString`]. See their documentation for more.
243244///
244245/// [`CStr`]: struct.CStr.html
245246/// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
247+ /// [`CString`]: struct.CString.html
248+ /// [`CString::from_vec_with_nul`]: struct.CString.html#method.from_vec_with_nul
246249///
247250/// # Examples
248251///
@@ -632,6 +635,77 @@ impl CString {
632635 let this = mem:: ManuallyDrop :: new ( self ) ;
633636 unsafe { ptr:: read ( & this. inner ) }
634637 }
638+
639+ /// Converts a `Vec` of `u8` to a `CString` without checking the invariants
640+ /// on the given `Vec`.
641+ ///
642+ /// # Safety
643+ ///
644+ /// The given `Vec` **must** have one nul byte as its last element.
645+ /// This means it cannot be empty nor have any other nul byte anywhere else.
646+ ///
647+ /// # Example
648+ ///
649+ /// ```
650+ /// use std::ffi::CString;
651+ /// assert_eq!(
652+ /// unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
653+ /// unsafe { CString::from_vec_unchecked(b"abc".to_vec()) }
654+ /// );
655+ /// ```
656+ #[ stable( feature = "cstring_from_vec_with_nul" , since = "1.46.0" ) ]
657+ pub unsafe fn from_vec_with_nul_unchecked ( v : Vec < u8 > ) -> Self {
658+ Self { inner : v. into_boxed_slice ( ) }
659+ }
660+
661+ /// Attempts to converts a `Vec` of `u8` to a `CString`.
662+ ///
663+ /// Runtime checks are present to ensure there is only one nul byte in the
664+ /// `Vec`, its last element.
665+ ///
666+ /// # Errors
667+ ///
668+ /// If a nul byte is present and not the last element or no nul bytes
669+ /// is present, an error will be returned.
670+ ///
671+ /// # Examples
672+ ///
673+ /// A successful conversion will produce the same result as [`new`] when
674+ /// called without the ending nul byte.
675+ ///
676+ /// ```
677+ /// use std::ffi::CString;
678+ /// assert_eq!(
679+ /// CString::from_vec_with_nul(b"abc\0".to_vec())
680+ /// .expect("CString::from_vec_with_nul failed"),
681+ /// CString::new(b"abc".to_vec())
682+ /// );
683+ /// ```
684+ ///
685+ /// A incorrectly formatted vector will produce an error.
686+ ///
687+ /// ```
688+ /// use std::ffi::{CString, FromBytesWithNulError};
689+ /// // Interior nul byte
690+ /// let _: FromBytesWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
691+ /// // No nul byte
692+ /// let _: FromBytesWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
693+ /// ```
694+ ///
695+ /// [`new`]: #method.new
696+ #[ stable( feature = "cstring_from_vec_with_nul" , since = "1.46.0" ) ]
697+ pub fn from_vec_with_nul ( v : Vec < u8 > ) -> Result < Self , FromBytesWithNulError > {
698+ let nul_pos = memchr:: memchr ( 0 , & v) ;
699+ match nul_pos {
700+ Some ( nul_pos) if nul_pos + 1 == v. len ( ) => {
701+ // SAFETY: We know there is only one nul byte, at the end
702+ // of the vec.
703+ Ok ( unsafe { Self :: from_vec_with_nul_unchecked ( v) } )
704+ }
705+ Some ( nul_pos) => Err ( FromBytesWithNulError :: interior_nul ( nul_pos) ) ,
706+ None => Err ( FromBytesWithNulError :: not_nul_terminated ( ) ) ,
707+ }
708+ }
635709}
636710
637711// Turns this `CString` into an empty string to prevent
0 commit comments