@@ -1058,7 +1058,9 @@ where
10581058 P : Pattern < Searcher < ' a > : fmt:: Debug > ,
10591059{
10601060 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1061- f. debug_tuple ( "MatchIndicesInternal" ) . field ( & self . 0 ) . finish ( )
1061+ f. debug_tuple ( "MatchIndicesInternal" )
1062+ . field ( & self . 0 )
1063+ . finish ( )
10621064 }
10631065}
10641066
@@ -1435,7 +1437,9 @@ impl<'a, P: Pattern> Iterator for SplitInclusive<'a, P> {
14351437#[ stable( feature = "split_inclusive" , since = "1.51.0" ) ]
14361438impl < ' a , P : Pattern < Searcher < ' a > : fmt:: Debug > > fmt:: Debug for SplitInclusive < ' a , P > {
14371439 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1438- f. debug_struct ( "SplitInclusive" ) . field ( "0" , & self . 0 ) . finish ( )
1440+ f. debug_struct ( "SplitInclusive" )
1441+ . field ( "0" , & self . 0 )
1442+ . finish ( )
14391443 }
14401444}
14411445
@@ -1613,3 +1617,261 @@ macro_rules! escape_types_impls {
16131617}
16141618
16151619escape_types_impls ! ( EscapeDebug , EscapeDefault , EscapeUnicode ) ;
1620+
1621+ #[ cfg( kani) ]
1622+ #[ unstable( feature = "kani" , issue = "none" ) ]
1623+ pub mod verify {
1624+ use super :: * ;
1625+
1626+ // ========== Chars ==========
1627+
1628+ /// Verify safety of Chars::next.
1629+ /// Unsafe ops: next_code_point + char::from_u32_unchecked.
1630+ #[ kani:: proof]
1631+ #[ kani:: unwind( 5 ) ]
1632+ fn check_chars_next ( ) {
1633+ let c: char = kani:: any ( ) ;
1634+ let mut buf = [ 0u8 ; 4 ] ;
1635+ let s = c. encode_utf8 ( & mut buf) ;
1636+ let mut chars = s. chars ( ) ;
1637+ let result = chars. next ( ) ;
1638+ assert_eq ! ( result, Some ( c) ) ;
1639+ assert ! ( chars. next( ) . is_none( ) ) ;
1640+ }
1641+
1642+ /// Verify safety of Chars::next_back.
1643+ /// Unsafe ops: next_code_point_reverse + char::from_u32_unchecked.
1644+ #[ kani:: proof]
1645+ #[ kani:: unwind( 5 ) ]
1646+ fn check_chars_next_back ( ) {
1647+ let c: char = kani:: any ( ) ;
1648+ let mut buf = [ 0u8 ; 4 ] ;
1649+ let s = c. encode_utf8 ( & mut buf) ;
1650+ let mut chars = s. chars ( ) ;
1651+ let result = chars. next_back ( ) ;
1652+ assert_eq ! ( result, Some ( c) ) ;
1653+ assert ! ( chars. next_back( ) . is_none( ) ) ;
1654+ }
1655+
1656+ /// Verify safety of Chars::advance_by (small input, final loop path).
1657+ /// Unsafe ops: self.iter.advance_by(slurp).unwrap_unchecked().
1658+ #[ kani:: proof]
1659+ #[ kani:: unwind( 5 ) ]
1660+ fn check_chars_advance_by ( ) {
1661+ let c: char = kani:: any ( ) ;
1662+ let mut buf = [ 0u8 ; 4 ] ;
1663+ let s = c. encode_utf8 ( & mut buf) ;
1664+ let mut chars = s. chars ( ) ;
1665+ let n: usize = kani:: any ( ) ;
1666+ kani:: assume ( n <= 4 ) ;
1667+ let _ = chars. advance_by ( n) ;
1668+ }
1669+
1670+ /// Verify safety of Chars::advance_by (large input, CHUNK_SIZE=32 branch).
1671+ /// Unsafe ops: self.iter.advance_by(bytes_skipped).unwrap_unchecked(),
1672+ /// self.iter.advance_by(1).unwrap_unchecked().
1673+ #[ kani:: proof]
1674+ #[ kani:: unwind( 34 ) ]
1675+ fn check_chars_advance_by_large ( ) {
1676+ // 33 ASCII bytes exercises the CHUNK_SIZE=32 branch
1677+ let s = "abcdefghijklmnopqrstuvwxyz0123456" ;
1678+ let mut chars = s. chars ( ) ;
1679+ let _ = chars. advance_by ( 33 ) ;
1680+ }
1681+
1682+ /// Verify safety of Chars::as_str.
1683+ /// Unsafe ops: from_utf8_unchecked(self.iter.as_slice()).
1684+ #[ kani:: proof]
1685+ #[ kani:: unwind( 5 ) ]
1686+ fn check_chars_as_str ( ) {
1687+ let c: char = kani:: any ( ) ;
1688+ let mut buf = [ 0u8 ; 4 ] ;
1689+ let s = c. encode_utf8 ( & mut buf) ;
1690+ let len = s. len ( ) ;
1691+ let mut chars = s. chars ( ) ;
1692+ let s1 = chars. as_str ( ) ;
1693+ assert_eq ! ( s1. len( ) , len) ;
1694+ let _ = chars. next ( ) ;
1695+ let s2 = chars. as_str ( ) ;
1696+ assert_eq ! ( s2. len( ) , 0 ) ;
1697+ }
1698+
1699+ // ========== SplitInternal ==========
1700+
1701+ /// Verify safety of SplitInternal::get_end.
1702+ /// Unsafe ops: get_unchecked(self.start..self.end).
1703+ /// Exercised when pattern has no matches in the haystack.
1704+ #[ kani:: proof]
1705+ #[ kani:: unwind( 5 ) ]
1706+ fn check_split_internal_get_end ( ) {
1707+ let mut split = "ab" . split ( 'x' ) ;
1708+ let result = split. next ( ) ; // no match -> calls get_end
1709+ assert ! ( result. is_some( ) ) ;
1710+ assert ! ( split. next( ) . is_none( ) ) ;
1711+ }
1712+
1713+ /// Verify safety of SplitInternal::next.
1714+ /// Unsafe ops: get_unchecked(self.start..a) and get_end fallback.
1715+ #[ kani:: proof]
1716+ #[ kani:: unwind( 5 ) ]
1717+ fn check_split_internal_next ( ) {
1718+ let c: char = kani:: any ( ) ;
1719+ kani:: assume ( c. is_ascii ( ) ) ;
1720+ let mut split = "ab" . split ( c) ;
1721+ let _ = split. next ( ) ;
1722+ let _ = split. next ( ) ;
1723+ let _ = split. next ( ) ;
1724+ }
1725+
1726+ /// Verify safety of SplitInternal::next_inclusive.
1727+ /// Unsafe ops: get_unchecked(self.start..b) and get_end fallback.
1728+ #[ kani:: proof]
1729+ #[ kani:: unwind( 5 ) ]
1730+ fn check_split_internal_next_inclusive ( ) {
1731+ let c: char = kani:: any ( ) ;
1732+ kani:: assume ( c. is_ascii ( ) ) ;
1733+ let mut split = "ab" . split_inclusive ( c) ;
1734+ let _ = split. next ( ) ;
1735+ let _ = split. next ( ) ;
1736+ let _ = split. next ( ) ;
1737+ }
1738+
1739+ /// Verify safety of SplitInternal::next_back.
1740+ /// Unsafe ops: get_unchecked(b..self.end) and get_unchecked(self.start..self.end).
1741+ #[ kani:: proof]
1742+ #[ kani:: unwind( 5 ) ]
1743+ fn check_split_internal_next_back ( ) {
1744+ let c: char = kani:: any ( ) ;
1745+ kani:: assume ( c. is_ascii ( ) ) ;
1746+ let mut split = "ab" . split ( c) ;
1747+ let _ = split. next_back ( ) ;
1748+ let _ = split. next_back ( ) ;
1749+ let _ = split. next_back ( ) ;
1750+ }
1751+
1752+ /// Verify safety of SplitInternal::next_back (allow_trailing_empty=false path).
1753+ /// Exercises the recursive next_back call via split_terminator.
1754+ #[ kani:: proof]
1755+ #[ kani:: unwind( 5 ) ]
1756+ fn check_split_internal_next_back_terminator ( ) {
1757+ let c: char = kani:: any ( ) ;
1758+ kani:: assume ( c. is_ascii ( ) ) ;
1759+ let mut split = "ab" . split_terminator ( c) ;
1760+ let _ = split. next_back ( ) ;
1761+ let _ = split. next_back ( ) ;
1762+ let _ = split. next_back ( ) ;
1763+ }
1764+
1765+ /// Verify safety of SplitInternal::next_back_inclusive.
1766+ /// Unsafe ops: get_unchecked(b..self.end) and get_unchecked(self.start..self.end).
1767+ /// split_inclusive sets allow_trailing_empty=false, exercising the recursive path.
1768+ #[ kani:: proof]
1769+ #[ kani:: unwind( 5 ) ]
1770+ fn check_split_internal_next_back_inclusive ( ) {
1771+ let c: char = kani:: any ( ) ;
1772+ kani:: assume ( c. is_ascii ( ) ) ;
1773+ let mut split = "ab" . split_inclusive ( c) ;
1774+ let _ = split. next_back ( ) ;
1775+ let _ = split. next_back ( ) ;
1776+ let _ = split. next_back ( ) ;
1777+ }
1778+
1779+ /// Verify safety of SplitInternal::remainder.
1780+ /// Unsafe ops: get_unchecked(self.start..self.end).
1781+ #[ kani:: proof]
1782+ #[ kani:: unwind( 5 ) ]
1783+ fn check_split_internal_remainder ( ) {
1784+ let c: char = kani:: any ( ) ;
1785+ kani:: assume ( c. is_ascii ( ) ) ;
1786+ let mut split = "ab" . split ( c) ;
1787+ let _ = split. remainder ( ) ;
1788+ let _ = split. next ( ) ;
1789+ let _ = split. remainder ( ) ;
1790+ }
1791+
1792+ // ========== MatchIndicesInternal ==========
1793+
1794+ /// Verify safety of MatchIndicesInternal::next.
1795+ /// Unsafe ops: get_unchecked(start..end).
1796+ #[ kani:: proof]
1797+ #[ kani:: unwind( 5 ) ]
1798+ fn check_match_indices_internal_next ( ) {
1799+ let c: char = kani:: any ( ) ;
1800+ kani:: assume ( c. is_ascii ( ) ) ;
1801+ let mut mi = "ab" . match_indices ( c) ;
1802+ let _ = mi. next ( ) ;
1803+ let _ = mi. next ( ) ;
1804+ let _ = mi. next ( ) ;
1805+ }
1806+
1807+ /// Verify safety of MatchIndicesInternal::next_back.
1808+ /// Unsafe ops: get_unchecked(start..end).
1809+ #[ kani:: proof]
1810+ #[ kani:: unwind( 5 ) ]
1811+ fn check_match_indices_internal_next_back ( ) {
1812+ let c: char = kani:: any ( ) ;
1813+ kani:: assume ( c. is_ascii ( ) ) ;
1814+ let mut mi = "ab" . match_indices ( c) ;
1815+ let _ = mi. next_back ( ) ;
1816+ let _ = mi. next_back ( ) ;
1817+ let _ = mi. next_back ( ) ;
1818+ }
1819+
1820+ // ========== MatchesInternal ==========
1821+
1822+ /// Verify safety of MatchesInternal::next.
1823+ /// Unsafe ops: get_unchecked(a..b).
1824+ #[ kani:: proof]
1825+ #[ kani:: unwind( 5 ) ]
1826+ fn check_matches_internal_next ( ) {
1827+ let c: char = kani:: any ( ) ;
1828+ kani:: assume ( c. is_ascii ( ) ) ;
1829+ let mut m = "ab" . matches ( c) ;
1830+ let _ = m. next ( ) ;
1831+ let _ = m. next ( ) ;
1832+ let _ = m. next ( ) ;
1833+ }
1834+
1835+ /// Verify safety of MatchesInternal::next_back.
1836+ /// Unsafe ops: get_unchecked(a..b).
1837+ #[ kani:: proof]
1838+ #[ kani:: unwind( 5 ) ]
1839+ fn check_matches_internal_next_back ( ) {
1840+ let c: char = kani:: any ( ) ;
1841+ kani:: assume ( c. is_ascii ( ) ) ;
1842+ let mut m = "ab" . matches ( c) ;
1843+ let _ = m. next_back ( ) ;
1844+ let _ = m. next_back ( ) ;
1845+ let _ = m. next_back ( ) ;
1846+ }
1847+
1848+ // ========== SplitAsciiWhitespace ==========
1849+
1850+ /// Verify safety of SplitAsciiWhitespace::remainder.
1851+ /// Unsafe ops: from_utf8_unchecked(&self.inner.iter.iter.v).
1852+ #[ kani:: proof]
1853+ #[ kani:: unwind( 5 ) ]
1854+ fn check_split_ascii_whitespace_remainder ( ) {
1855+ let mut split = "a b" . split_ascii_whitespace ( ) ;
1856+ let _ = split. remainder ( ) ;
1857+ let _ = split. next ( ) ;
1858+ let _ = split. remainder ( ) ;
1859+ let _ = split. next ( ) ;
1860+ let _ = split. remainder ( ) ;
1861+ }
1862+
1863+ // ========== Bytes ==========
1864+
1865+ /// Verify safety contract of Bytes::__iterator_get_unchecked.
1866+ /// Contract: #[requires(idx < self.0.len())].
1867+ #[ kani:: proof]
1868+ fn check_bytes_iterator_get_unchecked ( ) {
1869+ let s = "abcd" ;
1870+ let mut bytes = s. bytes ( ) ;
1871+ let idx: usize = kani:: any ( ) ;
1872+ kani:: assume ( idx < bytes. len ( ) ) ;
1873+ unsafe {
1874+ let _ = bytes. __iterator_get_unchecked ( idx) ;
1875+ }
1876+ }
1877+ }
0 commit comments