//! Memory-related data structures

pub use abi::mem::{MappingFlags, MappingSource};

#[cfg(any(feature = "rustc-dep-of-std", rust_analyzer))]
mod intrinsics {
    use core::ffi::{c_char, c_void};

    #[unsafe(no_mangle)]
    unsafe extern "C" fn bcmp(p0: *const c_void, p1: *const c_void, len: usize) -> i32 {
        unsafe { memcmp(p0, p1, len) }
    }

    #[unsafe(no_mangle)]
    unsafe extern "C" fn memcmp(p0: *const c_void, p1: *const c_void, len: usize) -> i32 {
        let mut offset = 0;

        if len == 0 {
            return 0;
        }

        while offset < len {
            let c0 = unsafe { (p0 as *const u8).add(offset).read_volatile() };
            let c1 = unsafe { (p1 as *const u8).add(offset).read_volatile() };

            if c0 > c1 {
                return (c0 - c1) as i32;
            } else if c0 < c1 {
                return -((c1 - c0) as i32);
            }

            offset += 1;
        }

        0
    }

    #[unsafe(no_mangle)]
    pub unsafe extern "C" fn memcpy(p0: *mut c_void, p1: *const c_void, len: usize) -> *mut c_void {
        let p0 = p0.cast::<u8>();
        let p1 = p1.cast::<u8>();
        let mut offset = 0;
        while offset < len {
            unsafe {
                p0.add(offset)
                    .write_volatile(p1.add(offset).read_volatile());
            }
            offset += 1;
        }
        p0.cast()
        // compiler_builtins::mem::memcpy(p0 as _, p1 as _, len) as _
    }

    #[unsafe(no_mangle)]
    unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
        let dst = dst.cast::<u8>();
        let src = src.cast::<u8>();

        if dst.addr() == src.addr() || n == 0 {
            return dst.cast();
        }

        if (dst as usize) < (src as usize) {
            // Copy forward
            let mut i = 0;
            while i < n {
                unsafe { *dst.add(i) = *src.add(i) };
                i += 1;
            }
        } else {
            // Copy backward (handles overlap)
            let mut i = n;
            while i != 0 {
                i -= 1;
                unsafe { *dst.add(i) = *src.add(i) };
            }
        }

        dst.cast()
    }

    #[unsafe(no_mangle)]
    unsafe extern "C" fn memset(dst: *mut c_void, val: i32, len: usize) -> *mut c_void {
        let mut offset = 0;
        while offset < len {
            unsafe { (dst as *mut u8).add(offset).write_volatile(val as u8) };
            offset += 1;
        }
        dst
    }

    #[unsafe(no_mangle)]
    unsafe extern "C" fn strlen(mut s: *mut c_char) -> usize {
        if s.is_null() {
            return 0;
        }
        let mut len = 0;
        unsafe {
            while s.read() != 0 {
                len += 1;
                s = s.add(1);
            }
        }
        len
    }
}
