// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
use dlibc;
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
    let p = unsafe {
        dlibc::memchr(
            haystack.as_ptr() as *const dlibc::c_void,
            needle as dlibc::c_int,
            haystack.len(),
        )
    };
    if p.is_null() {
        None
    } else {
        Some(p.addr() - haystack.as_ptr().addr())
    }
}

pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
    #[cfg(target_os = "linux")]
    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
        // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
        if haystack.is_empty() {
            return None;
        }
        let p = unsafe {
            dlibc::memrchr(
                haystack.as_ptr() as *const dlibc::c_void,
                needle as dlibc::c_int,
                haystack.len(),
            )
        };
        // FIXME: this should *likely* use `offset_from`, but more
        // investigation is needed (including running tests in miri).
        if p.is_null() {
            None
        } else {
            Some(p.addr() - haystack.as_ptr().addr())
        }
    }

    #[cfg(not(target_os = "linux"))]
    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
        core::slice::memchr::memrchr(needle, haystack)
    }

    memrchr_specific(needle, haystack)
}
