1#[cfg(not(all(unix, feature = "libc")))]
7fn memchr_inner(needle: u8, haystack: &[u8]) -> Option<usize> {
8 haystack.iter().position(|val| needle == *val)
9}
10
11#[cfg(all(unix, feature = "libc"))]
12fn memchr_inner(needle: u8, haystack: &[u8]) -> Option<usize> {
13 let start = haystack.as_ptr();
14
15 let ptr = (unsafe { libc::memchr(start.cast(), needle as _, haystack.len()) })
17 .cast::<u8>()
18 .cast_const();
19
20 if ptr.is_null() {
21 None
22 } else {
23 unsafe {
30 Some(usize::try_from(ptr.offset_from(start)).unwrap_unchecked())
32 }
33 }
34}
35
36pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
37 let index = memchr_inner(needle, haystack)?;
38
39 unsafe {
45 if haystack.get(..=index).is_none() {
46 std::hint::unreachable_unchecked()
47 }
48 }
49
50 Some(index)
51}
52
53#[cfg(test)]
54mod 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}