@@ -234,15 +234,14 @@ pub struct NulError(usize, Vec<u8>);
234
234
235
235
/// An error indicating that a nul byte was not in the expected position.
236
236
///
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`] must have one and only one nul byte,
238
+ /// positioned at the end.
239
239
///
240
- /// This error is created by the
241
- /// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
242
- /// [`CStr`]. See its documentation for more.
240
+ /// This error is created by the [`from_bytes_with_nul`] method on [`CStr`].
241
+ /// See its documentation for more.
243
242
///
244
243
/// [`CStr`]: struct.CStr.html
245
- /// [`CStr:: from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
244
+ /// [`from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
246
245
///
247
246
/// # Examples
248
247
///
@@ -257,6 +256,32 @@ pub struct FromBytesWithNulError {
257
256
kind : FromBytesWithNulErrorKind ,
258
257
}
259
258
259
+ /// An error indicating that a nul byte was not in the expected position.
260
+ ///
261
+ /// The vector used to create a [`CString`] must have one and only one nul byte,
262
+ /// positioned at the end.
263
+ ///
264
+ /// This error is created by the [`from_vec_with_nul`] method on [`CString`].
265
+ /// See its documentation for more.
266
+ ///
267
+ /// [`CString`]: struct.CString.html
268
+ /// [`from_vec_with_nul`]: struct.CString.html#method.from_vec_with_nul
269
+ ///
270
+ /// # Examples
271
+ ///
272
+ /// ```
273
+ /// #![feature(cstring_from_vec_with_nul)]
274
+ /// use std::ffi::{CString, FromVecWithNulError};
275
+ ///
276
+ /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
277
+ /// ```
278
+ #[ derive( Clone , PartialEq , Eq , Debug ) ]
279
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
280
+ pub struct FromVecWithNulError {
281
+ error_kind : FromBytesWithNulErrorKind ,
282
+ bytes : Vec < u8 > ,
283
+ }
284
+
260
285
#[ derive( Clone , PartialEq , Eq , Debug ) ]
261
286
enum FromBytesWithNulErrorKind {
262
287
InteriorNul ( usize ) ,
@@ -272,6 +297,59 @@ impl FromBytesWithNulError {
272
297
}
273
298
}
274
299
300
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
301
+ impl FromVecWithNulError {
302
+ /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
303
+ ///
304
+ /// # Examples
305
+ ///
306
+ /// Basic usage:
307
+ ///
308
+ /// ```
309
+ /// #![feature(cstring_from_vec_with_nul)]
310
+ /// use std::ffi::CString;
311
+ ///
312
+ /// // Some invalid bytes in a vector
313
+ /// let bytes = b"f\0oo".to_vec();
314
+ ///
315
+ /// let value = CString::from_vec_with_nul(bytes.clone());
316
+ ///
317
+ /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
318
+ /// ```
319
+ ///
320
+ /// [`CString`]: struct.CString.html
321
+ pub fn as_bytes ( & self ) -> & [ u8 ] {
322
+ & self . bytes [ ..]
323
+ }
324
+
325
+ /// Returns the bytes that were attempted to convert to a [`CString`].
326
+ ///
327
+ /// This method is carefully constructed to avoid allocation. It will
328
+ /// consume the error, moving out the bytes, so that a copy of the bytes
329
+ /// does not need to be made.
330
+ ///
331
+ /// # Examples
332
+ ///
333
+ /// Basic usage:
334
+ ///
335
+ /// ```
336
+ /// #![feature(cstring_from_vec_with_nul)]
337
+ /// use std::ffi::CString;
338
+ ///
339
+ /// // Some invalid bytes in a vector
340
+ /// let bytes = b"f\0oo".to_vec();
341
+ ///
342
+ /// let value = CString::from_vec_with_nul(bytes.clone());
343
+ ///
344
+ /// assert_eq!(bytes, value.unwrap_err().into_bytes());
345
+ /// ```
346
+ ///
347
+ /// [`CString`]: struct.CString.html
348
+ pub fn into_bytes ( self ) -> Vec < u8 > {
349
+ self . bytes
350
+ }
351
+ }
352
+
275
353
/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
276
354
///
277
355
/// `CString` is just a wrapper over a buffer of bytes with a nul
@@ -643,6 +721,86 @@ impl CString {
643
721
let this = mem:: ManuallyDrop :: new ( self ) ;
644
722
unsafe { ptr:: read ( & this. inner ) }
645
723
}
724
+
725
+ /// Converts a `Vec` of `u8` to a `CString` without checking the invariants
726
+ /// on the given `Vec`.
727
+ ///
728
+ /// # Safety
729
+ ///
730
+ /// The given `Vec` **must** have one nul byte as its last element.
731
+ /// This means it cannot be empty nor have any other nul byte anywhere else.
732
+ ///
733
+ /// # Example
734
+ ///
735
+ /// ```
736
+ /// #![feature(cstring_from_vec_with_nul)]
737
+ /// use std::ffi::CString;
738
+ /// assert_eq!(
739
+ /// unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
740
+ /// unsafe { CString::from_vec_unchecked(b"abc".to_vec()) }
741
+ /// );
742
+ /// ```
743
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
744
+ pub unsafe fn from_vec_with_nul_unchecked ( v : Vec < u8 > ) -> Self {
745
+ Self { inner : v. into_boxed_slice ( ) }
746
+ }
747
+
748
+ /// Attempts to converts a `Vec` of `u8` to a `CString`.
749
+ ///
750
+ /// Runtime checks are present to ensure there is only one nul byte in the
751
+ /// `Vec`, its last element.
752
+ ///
753
+ /// # Errors
754
+ ///
755
+ /// If a nul byte is present and not the last element or no nul bytes
756
+ /// is present, an error will be returned.
757
+ ///
758
+ /// # Examples
759
+ ///
760
+ /// A successful conversion will produce the same result as [`new`] when
761
+ /// called without the ending nul byte.
762
+ ///
763
+ /// ```
764
+ /// #![feature(cstring_from_vec_with_nul)]
765
+ /// use std::ffi::CString;
766
+ /// assert_eq!(
767
+ /// CString::from_vec_with_nul(b"abc\0".to_vec())
768
+ /// .expect("CString::from_vec_with_nul failed"),
769
+ /// CString::new(b"abc".to_vec()).expect("CString::new failed")
770
+ /// );
771
+ /// ```
772
+ ///
773
+ /// A incorrectly formatted vector will produce an error.
774
+ ///
775
+ /// ```
776
+ /// #![feature(cstring_from_vec_with_nul)]
777
+ /// use std::ffi::{CString, FromVecWithNulError};
778
+ /// // Interior nul byte
779
+ /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
780
+ /// // No nul byte
781
+ /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
782
+ /// ```
783
+ ///
784
+ /// [`new`]: #method.new
785
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
786
+ pub fn from_vec_with_nul ( v : Vec < u8 > ) -> Result < Self , FromVecWithNulError > {
787
+ let nul_pos = memchr:: memchr ( 0 , & v) ;
788
+ match nul_pos {
789
+ Some ( nul_pos) if nul_pos + 1 == v. len ( ) => {
790
+ // SAFETY: We know there is only one nul byte, at the end
791
+ // of the vec.
792
+ Ok ( unsafe { Self :: from_vec_with_nul_unchecked ( v) } )
793
+ }
794
+ Some ( nul_pos) => Err ( FromVecWithNulError {
795
+ error_kind : FromBytesWithNulErrorKind :: InteriorNul ( nul_pos) ,
796
+ bytes : v,
797
+ } ) ,
798
+ None => Err ( FromVecWithNulError {
799
+ error_kind : FromBytesWithNulErrorKind :: NotNulTerminated ,
800
+ bytes : v,
801
+ } ) ,
802
+ }
803
+ }
646
804
}
647
805
648
806
// Turns this `CString` into an empty string to prevent
@@ -976,6 +1134,23 @@ impl fmt::Display for FromBytesWithNulError {
976
1134
}
977
1135
}
978
1136
1137
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
1138
+ impl Error for FromVecWithNulError { }
1139
+
1140
+ #[ unstable( feature = "cstring_from_vec_with_nul" , issue = "73179" ) ]
1141
+ impl fmt:: Display for FromVecWithNulError {
1142
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1143
+ match self . error_kind {
1144
+ FromBytesWithNulErrorKind :: InteriorNul ( pos) => {
1145
+ write ! ( f, "data provided contains an interior nul byte at pos {}" , pos)
1146
+ }
1147
+ FromBytesWithNulErrorKind :: NotNulTerminated => {
1148
+ write ! ( f, "data provided is not nul terminated" )
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+
979
1154
impl IntoStringError {
980
1155
/// Consumes this error, returning original [`CString`] which generated the
981
1156
/// error.
0 commit comments