@@ -5,8 +5,11 @@ use crate::error::Error;
5
5
use crate :: ffi:: c_char;
6
6
use crate :: fmt;
7
7
use crate :: intrinsics;
8
+ use crate :: iter:: FusedIterator ;
9
+ use crate :: marker:: PhantomData ;
8
10
use crate :: ops;
9
11
use crate :: ptr:: addr_of;
12
+ use crate :: ptr:: NonNull ;
10
13
use crate :: slice;
11
14
use crate :: slice:: memchr;
12
15
use crate :: str;
@@ -504,6 +507,13 @@ impl CStr {
504
507
self . inner . as_ptr ( )
505
508
}
506
509
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
+
507
517
/// Returns the length of `self`. Like C's `strlen`, this does not include the nul terminator.
508
518
///
509
519
/// > **Note**: This method is currently implemented as a constant-time
@@ -617,6 +627,26 @@ impl CStr {
617
627
unsafe { & * ( addr_of ! ( self . inner) as * const [ u8 ] ) }
618
628
}
619
629
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
+
620
650
/// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
621
651
///
622
652
/// 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 {
735
765
intrinsics:: const_eval_select ( ( ptr, ) , strlen_ct, strlen_rt)
736
766
}
737
767
}
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