// SPDX-License-Identifier: (Apache-2.0 OR MIT)
// Copyright ijl (2019-2026), Ben Sully (2021), Marc Mueller (2023)

macro_rules! is_subclass_by_flag {
    ($tp_flags:expr, $flag:ident) => {
        unsafe { (($tp_flags & crate::ffi::$flag) != 0) }
    };
}

macro_rules! opt_enabled {
    ($var:expr, $flag:expr) => {
        $var & $flag != 0
    };
}

macro_rules! opt_disabled {
    ($var:expr, $flag:expr) => {
        $var & $flag == 0
    };
}

macro_rules! cold_path {
    () => {
        core::hint::cold_path();
    };
}

macro_rules! nonnull {
    ($exp:expr) => {
        unsafe { core::ptr::NonNull::new_unchecked($exp) }
    };
}

macro_rules! str_from_slice {
    ($ptr:expr, $size:expr) => {
        unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts($ptr, $size as usize)) }
    };
}

#[cfg(all(CPython, Py_3_13))]
macro_rules! pydict_contains {
    ($obj1:expr, $obj2:expr) => {
        unsafe { crate::ffi::PyDict_Contains(crate::ffi::PyType_GetDict($obj1), $obj2) == 1 }
    };
}

#[cfg(all(CPython, Py_3_12, not(Py_3_13)))]
macro_rules! pydict_contains {
    ($obj1:expr, $obj2:expr) => {
        unsafe {
            debug_assert!((*$obj2.cast::<crate::ffi::PyASCIIObject>()).hash != -1);
            crate::ffi::_PyDict_Contains_KnownHash(
                crate::ffi::PyType_GetDict($obj1),
                $obj2,
                (*$obj2.cast::<crate::ffi::PyASCIIObject>()).hash,
            ) == 1
        }
    };
}

#[cfg(all(CPython, not(Py_3_12)))]
macro_rules! pydict_contains {
    ($obj1:expr, $obj2:expr) => {
        unsafe {
            debug_assert!((*$obj2.cast::<crate::ffi::PyASCIIObject>()).hash != -1);
            crate::ffi::_PyDict_Contains_KnownHash(
                (*$obj1).tp_dict,
                $obj2,
                (*$obj2.cast::<crate::ffi::PyASCIIObject>()).hash,
            ) == 1
        }
    };
}

#[cfg(not(CPython))]
macro_rules! pydict_contains {
    ($obj1:expr, $obj2:expr) => {
        unsafe { crate::ffi::PyDict_Contains((*$obj1).tp_dict, $obj2) == 1 }
    };
}

#[cfg(Py_3_12)]
macro_rules! use_immortal {
    ($op:expr) => {
        unsafe { $op }
    };
}

#[cfg(not(Py_3_12))]
macro_rules! use_immortal {
    ($op:expr) => {
        unsafe {
            unsafe { crate::ffi::Py_INCREF($op) };
            $op
        }
    };
}

macro_rules! assume {
    ($expr:expr) => {
        debug_assert!($expr);
        unsafe {
            core::hint::assert_unchecked($expr);
        };
    };
}

macro_rules! unreachable_unchecked {
    () => {
        unsafe { core::hint::unreachable_unchecked() }
    };
}

#[inline(always)]
#[allow(clippy::cast_possible_wrap)]
pub(crate) const fn usize_to_isize(val: usize) -> isize {
    debug_assert!(val < (isize::MAX as usize));
    val as isize
}

#[inline(always)]
pub(crate) const fn isize_to_usize(val: isize) -> usize {
    debug_assert!(val >= 0);
    val.cast_unsigned()
}

macro_rules! write_double_digit {
    ($buf:ident, $value:expr) => {
        if $value < 10 {
            $buf.put_u8(b'0');
        }
        crate::serialize::writer::write_integer_u32($buf, $value);
    };
}

macro_rules! write_triple_digit {
    ($buf:ident, $value:expr) => {
        if $value < 100 {
            $buf.put_u8(b'0');
        }
        if $value < 10 {
            $buf.put_u8(b'0');
        }
        crate::serialize::writer::write_integer_u32($buf, $value);
    };
}
