Coverage Report

Created: 2026-08-31 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.53.1/src/util/memchr.rs
Line
Count
Source
1
//! Search for a byte in a byte array using libc.
2
//!
3
//! When nothing pulls in libc, then just use a trivial implementation. Note
4
//! that we only depend on libc on unix.
5
6
#[cfg(not(all(unix, feature = "libc")))]
7
fn memchr_inner(needle: u8, haystack: &[u8]) -> Option<usize> {
8
    haystack.iter().position(|val| needle == *val)
9
}
10
11
#[cfg(all(unix, feature = "libc"))]
12
0
fn memchr_inner(needle: u8, haystack: &[u8]) -> Option<usize> {
13
0
    let start = haystack.as_ptr();
14
15
    // SAFETY: `start` is valid for `haystack.len()` bytes.
16
0
    let ptr = (unsafe { libc::memchr(start.cast(), needle as _, haystack.len()) })
17
0
        .cast::<u8>()
18
0
        .cast_const();
19
20
0
    if ptr.is_null() {
21
0
        None
22
    } else {
23
        // SAFETY: `ptr` will always be in bounds, since libc guarantees that the ptr will either
24
        //          be to an element inside the array or the ptr will be null
25
        //          since the ptr is in bounds the offset must also always be non null
26
        //          and there can't be more than isize::MAX elements inside an array
27
        //          as rust guarantees that the maximum number of bytes a allocation
28
        //          may occupy is isize::MAX
29
        unsafe {
30
            // TODO(MSRV 1.87): When bumping MSRV, switch to `ptr.byte_offset_from_unsigned(start)`.
31
0
            Some(usize::try_from(ptr.offset_from(start)).unwrap_unchecked())
32
        }
33
    }
34
0
}
35
36
0
pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
37
0
    let index = memchr_inner(needle, haystack)?;
38
39
    // SAFETY: `memchr_inner` returns Some(index) and in that case index must point to an element in haystack
40
    //         or `memchr_inner` None which is guarded by the `?` operator above
41
    //         therefore the index must **always** point to an element in the array
42
    //         and so this indexing operation is safe
43
    // TODO(MSRV 1.81): When bumping MSRV, switch to `std::hint::assert_unchecked(haystack.get(..=index).is_some());`
44
    unsafe {
45
0
        if haystack.get(..=index).is_none() {
46
0
            std::hint::unreachable_unchecked()
47
0
        }
48
    }
49
50
0
    Some(index)
51
0
}
52
53
#[cfg(test)]
54
mod tests {
55
    use super::memchr;
56
57
    #[test]
58
    fn memchr_test() {
59
        let haystack = b"123abc456\0\xffabc\n";
60
61
        assert_eq!(memchr(b'1', haystack), Some(0));
62
        assert_eq!(memchr(b'2', haystack), Some(1));
63
        assert_eq!(memchr(b'3', haystack), Some(2));
64
        assert_eq!(memchr(b'4', haystack), Some(6));
65
        assert_eq!(memchr(b'5', haystack), Some(7));
66
        assert_eq!(memchr(b'6', haystack), Some(8));
67
        assert_eq!(memchr(b'7', haystack), None);
68
        assert_eq!(memchr(b'a', haystack), Some(3));
69
        assert_eq!(memchr(b'b', haystack), Some(4));
70
        assert_eq!(memchr(b'c', haystack), Some(5));
71
        assert_eq!(memchr(b'd', haystack), None);
72
        assert_eq!(memchr(b'A', haystack), None);
73
        assert_eq!(memchr(0, haystack), Some(9));
74
        assert_eq!(memchr(0xff, haystack), Some(10));
75
        assert_eq!(memchr(0xfe, haystack), None);
76
        assert_eq!(memchr(1, haystack), None);
77
        assert_eq!(memchr(b'\n', haystack), Some(14));
78
        assert_eq!(memchr(b'\r', haystack), None);
79
    }
80
81
    #[test]
82
    fn memchr_all() {
83
        let mut arr = Vec::new();
84
        for b in 0..=255 {
85
            arr.push(b);
86
        }
87
        for b in 0..=255 {
88
            assert_eq!(memchr(b, &arr), Some(b as usize));
89
        }
90
        arr.reverse();
91
        for b in 0..=255 {
92
            assert_eq!(memchr(b, &arr), Some(255 - b as usize));
93
        }
94
    }
95
96
    #[test]
97
    fn memchr_empty() {
98
        for b in 0..=255 {
99
            assert_eq!(memchr(b, b""), None);
100
        }
101
    }
102
}