| 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 | pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { | 
|---|
| 8 | haystack.iter().position(|val: &u8| needle == *val) | 
|---|
| 9 | } | 
|---|
| 10 |  | 
|---|
| 11 | #[ cfg(all(unix, feature = "libc"))] | 
|---|
| 12 | pub(crate) fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { | 
|---|
| 13 | let start = haystack.as_ptr(); | 
|---|
| 14 |  | 
|---|
| 15 | // SAFETY: `start` is valid for `haystack.len()` bytes. | 
|---|
| 16 | let ptr = unsafe { libc::memchr(start.cast(), needle as _, haystack.len()) }; | 
|---|
| 17 |  | 
|---|
| 18 | if ptr.is_null() { | 
|---|
| 19 | None | 
|---|
| 20 | } else { | 
|---|
| 21 | Some(ptr as usize - start as usize) | 
|---|
| 22 | } | 
|---|
| 23 | } | 
|---|
| 24 |  | 
|---|
| 25 | #[ cfg(test)] | 
|---|
| 26 | mod tests { | 
|---|
| 27 | use super::memchr; | 
|---|
| 28 |  | 
|---|
| 29 | #[ test] | 
|---|
| 30 | fn memchr_test() { | 
|---|
| 31 | let haystack = b"123abc456\0\xff abc\n "; | 
|---|
| 32 |  | 
|---|
| 33 | assert_eq!(memchr( b'1', haystack), Some(0)); | 
|---|
| 34 | assert_eq!(memchr( b'2', haystack), Some(1)); | 
|---|
| 35 | assert_eq!(memchr( b'3', haystack), Some(2)); | 
|---|
| 36 | assert_eq!(memchr( b'4', haystack), Some(6)); | 
|---|
| 37 | assert_eq!(memchr( b'5', haystack), Some(7)); | 
|---|
| 38 | assert_eq!(memchr( b'6', haystack), Some(8)); | 
|---|
| 39 | assert_eq!(memchr( b'7', haystack), None); | 
|---|
| 40 | assert_eq!(memchr( b'a', haystack), Some(3)); | 
|---|
| 41 | assert_eq!(memchr( b'b', haystack), Some(4)); | 
|---|
| 42 | assert_eq!(memchr( b'c', haystack), Some(5)); | 
|---|
| 43 | assert_eq!(memchr( b'd', haystack), None); | 
|---|
| 44 | assert_eq!(memchr( b'A', haystack), None); | 
|---|
| 45 | assert_eq!(memchr(0, haystack), Some(9)); | 
|---|
| 46 | assert_eq!(memchr(0xff, haystack), Some(10)); | 
|---|
| 47 | assert_eq!(memchr(0xfe, haystack), None); | 
|---|
| 48 | assert_eq!(memchr(1, haystack), None); | 
|---|
| 49 | assert_eq!(memchr( b'\n ', haystack), Some(14)); | 
|---|
| 50 | assert_eq!(memchr( b'\r ', haystack), None); | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 | #[ test] | 
|---|
| 54 | fn memchr_all() { | 
|---|
| 55 | let mut arr = Vec::new(); | 
|---|
| 56 | for b in 0..=255 { | 
|---|
| 57 | arr.push(b); | 
|---|
| 58 | } | 
|---|
| 59 | for b in 0..=255 { | 
|---|
| 60 | assert_eq!(memchr(b, &arr), Some(b as usize)); | 
|---|
| 61 | } | 
|---|
| 62 | arr.reverse(); | 
|---|
| 63 | for b in 0..=255 { | 
|---|
| 64 | assert_eq!(memchr(b, &arr), Some(255 - b as usize)); | 
|---|
| 65 | } | 
|---|
| 66 | } | 
|---|
| 67 |  | 
|---|
| 68 | #[ test] | 
|---|
| 69 | fn memchr_empty() { | 
|---|
| 70 | for b in 0..=255 { | 
|---|
| 71 | assert_eq!(memchr(b, b""), None); | 
|---|
| 72 | } | 
|---|
| 73 | } | 
|---|
| 74 | } | 
|---|
| 75 |  | 
|---|