@@ -5,8 +5,11 @@ use crate::error::Error;
55use crate :: ffi:: c_char;
66use crate :: fmt;
77use crate :: intrinsics;
8+ use crate :: iter:: FusedIterator ;
9+ use crate :: marker:: PhantomData ;
810use crate :: ops;
911use crate :: ptr:: addr_of;
12+ use crate :: ptr:: NonNull ;
1013use crate :: slice;
1114use crate :: slice:: memchr;
1215use crate :: str;
@@ -504,6 +507,13 @@ impl CStr {
504507 self . inner . as_ptr ( )
505508 }
506509
510+ /// We could eventually expose this publicly, if we wanted.
511+ #[ inline]
512+ #[ must_use]
513+ const fn as_non_null_ptr ( & self ) -> NonNull < c_char > {
514+ NonNull :: from ( & self . inner ) . as_non_null_ptr ( )
515+ }
516+
507517 /// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator.
508518 ///
509519 /// > **Note**: This method is currently implemented as a constant-time
@@ -617,6 +627,26 @@ impl CStr {
617627 unsafe { & * ( addr_of ! ( self . inner) as * const [ u8 ] ) }
618628 }
619629
630+ /// Iterates over the bytes in this C string.
631+ ///
632+ /// The returned iterator will **not** contain the trailing nul terminator
633+ /// that this C string has.
634+ ///
635+ /// # Examples
636+ ///
637+ /// ```
638+ /// #![feature(cstr_bytes)]
639+ /// use std::ffi::CStr;
640+ ///
641+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
642+ /// assert!(cstr.bytes().eq(*b"foo"));
643+ /// ```
644+ #[ inline]
645+ #[ unstable( feature = "cstr_bytes" , issue = "112115" ) ]
646+ pub fn bytes ( & self ) -> Bytes < ' _ > {
647+ Bytes :: new ( self )
648+ }
649+
620650 /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
621651 ///
622652 /// If the contents of the `CStr` are valid UTF-8 data, this
@@ -735,3 +765,64 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize {
735765 intrinsics:: const_eval_select ( ( ptr, ) , strlen_ct, strlen_rt)
736766 }
737767}
768+
769+ /// An iterator over the bytes of a [`CStr`], without the nul terminator.
770+ ///
771+ /// This struct is created by the [`bytes`] method on [`CStr`].
772+ /// See its documentation for more.
773+ ///
774+ /// [`bytes`]: CStr::bytes
775+ #[ must_use = "iterators are lazy and do nothing unless consumed" ]
776+ #[ unstable( feature = "cstr_bytes" , issue = "112115" ) ]
777+ #[ derive( Clone , Debug ) ]
778+ pub struct Bytes < ' a > {
779+ // since we know the string is nul-terminated, we only need one pointer
780+ ptr : NonNull < u8 > ,
781+ phantom : PhantomData < & ' a u8 > ,
782+ }
783+ impl < ' a > Bytes < ' a > {
784+ #[ inline]
785+ fn new ( s : & ' a CStr ) -> Self {
786+ Self { ptr : s. as_non_null_ptr ( ) . cast ( ) , phantom : PhantomData }
787+ }
788+
789+ #[ inline]
790+ fn is_empty ( & self ) -> bool {
791+ // SAFETY: We uphold that the pointer is always valid to dereference
792+ // by starting with a valid C string and then never incrementing beyond
793+ // the nul terminator.
794+ unsafe { self . ptr . read ( ) == 0 }
795+ }
796+ }
797+
798+ #[ unstable( feature = "cstr_bytes" , issue = "112115" ) ]
799+ impl Iterator for Bytes < ' _ > {
800+ type Item = u8 ;
801+
802+ #[ inline]
803+ fn next ( & mut self ) -> Option < u8 > {
804+ // SAFETY: We only choose a pointer from a valid C string, which must
805+ // be non-null and contain at least one value. Since we always stop at
806+ // the nul terminator, which is guaranteed to exist, we can assume that
807+ // the pointer is non-null and valid. This lets us safely dereference
808+ // it and assume that adding 1 will create a new, non-null, valid
809+ // pointer.
810+ unsafe {
811+ let ret = self . ptr . read ( ) ;
812+ if ret == 0 {
813+ None
814+ } else {
815+ self . ptr = self . ptr . offset ( 1 ) ;
816+ Some ( ret)
817+ }
818+ }
819+ }
820+
821+ #[ inline]
822+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
823+ if self . is_empty ( ) { ( 0 , Some ( 0 ) ) } else { ( 1 , None ) }
824+ }
825+ }
826+
827+ #[ unstable( feature = "cstr_bytes" , issue = "112115" ) ]
828+ impl FusedIterator for Bytes < ' _ > { }
0 commit comments