use core::{
    ffi::{c_int, c_void},
    ptr::null_mut,
};

#[no_mangle]
unsafe extern "C" fn memccpy(
    dst: *mut c_void,
    src: *const c_void,
    c: c_int,
    mut n: usize,
) -> *mut c_void {
    let c = c as u8;
    let mut dst = dst as *mut u8;
    let mut src = src as *mut u8;

    if dst.is_null() || src.is_null() {
        panic!();
    }

    while n != 0 {
        let ch = *src;
        *dst = ch;
        dst = dst.add(1);

        if ch == c {
            return dst as _;
        }

        src = src.add(1);
        n -= 1;
    }

    null_mut()
}

#[no_mangle]
unsafe extern "C" fn memchr(s: *const c_void, c: c_int, mut n: usize) -> *mut c_void {
    if s.is_null() {
        panic!();
    }

    let c = c as u8;
    let mut s = s as *const u8;

    while n != 0 {
        if *s == c {
            return s as _;
        }
        s = s.add(1);
        n -= 1;
    }

    null_mut()
}

#[no_mangle]
pub(super) unsafe extern "C" fn mempcpy(
    dst: *mut c_void,
    src: *const c_void,
    n: usize,
) -> *mut c_void {
    if dst.is_null() || src.is_null() {
        panic!();
    }
    let dst = dst as *mut u8;
    let src = src as *const u8;

    for i in 0..n {
        *dst.add(i) = *src.add(i);
    }
    dst.add(n) as _
}

#[no_mangle]
pub unsafe extern "C" fn memset(dst: *mut c_void, val: c_int, n: usize) -> *mut c_void {
    compiler_builtins::mem::memset(dst.cast(), val, n).cast()
}

#[no_mangle]
pub unsafe extern "C" fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
    compiler_builtins::mem::memcpy(dst.cast(), src.cast(), n).cast()
}

#[no_mangle]
pub unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
    compiler_builtins::mem::memmove(dst.cast(), src.cast(), n).cast()
}

#[no_mangle]
pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
    compiler_builtins::mem::memcmp(s1.cast(), s2.cast(), n)
}

#[no_mangle]
pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
    compiler_builtins::mem::bcmp(s1.cast(), s2.cast(), n)
}
