// Copyright 2025 Gabriel Bjørnager Jensen.

use crate::{Array, Uint};

use core::any::Any;
use core::fmt::{
	Binary,
	Debug,
	Display,
	LowerExp,
	LowerHex,
	Octal,
	UpperExp,
	UpperHex,
};
use core::iter::{Product, Sum};
use core::num::ParseIntError;
use core::ops::{
	Add,
	AddAssign,
	BitAnd,
	BitAndAssign,
	BitOr,
	BitOrAssign,
	BitXor,
	BitXorAssign,
	Div,
	DivAssign,
	Mul,
	MulAssign,
	Neg,
	Not,
	Rem,
	RemAssign,
	Shl,
	ShlAssign,
	Shr,
	ShrAssign,
	Sub,
	SubAssign,
};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::str::FromStr;

/// A generic, signed integer.
///
/// This trait abstracts the interfaces defined by [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], and [`isize`] so that these may be used as a single type.
///
/// See also [`IntLeast16`](crate::IntLeast16), [`IntLeast32`](crate::IntLeast32), and [`IntLeast64`](crate::IntLeast64).
///
/// # Safety
///
/// [`Uint`](Self::Uint) must be *the* unsigned counterpart to `Self` so that transmutations between the two are always valid.
///
/// Furthermore, all items must behave exactly as their standard counterparts.
pub unsafe trait Int
where
	Self:
		crate::SealedInt
		+ 'static
		+ Any
		+ Binary
		+ Copy
		+ Debug
		+ Default
		+ Display
		+ Eq
		+ From<i8>
		+ FromStr
		+ LowerExp
		+ LowerHex
		+ Octal
		+ Ord
		+ PartialEq
		+ PartialOrd
		+ Product
		+ RefUnwindSafe
		+ Send
		+ Sync
		+ Sum
		+ Unpin
		+ UnwindSafe
		+ UpperExp
		+ UpperHex
		// Arithmetic operators:
		+ Add<           Output = Self>
		+ BitAnd<        Output = Self>
		+ BitOr<         Output = Self>
		+ BitXor<        Output = Self>
		+ Div<           Output = Self>
		+ Mul<           Output = Self>
		+ Neg<           Output = Self>
		+ Not<           Output = Self>
		+ Rem<           Output = Self>
		+ Shl<           Output = Self>
		+ Shl<   u8,     Output = Self>
		+ Shl<   u16,    Output = Self>
		+ Shl<   u32,    Output = Self>
		+ Shl<   u64,    Output = Self>
		+ Shl<   u128,   Output = Self>
		+ Shl<   usize,  Output = Self>
		+ Shl<   i8,     Output = Self>
		+ Shl<   i16,    Output = Self>
		+ Shl<   i32,    Output = Self>
		+ Shl<   i64,    Output = Self>
		+ Shl<   i128,   Output = Self>
		+ Shl<   isize,  Output = Self>
		+ Shr<           Output = Self>
		+ Shr<   u8,     Output = Self>
		+ Shr<   u16,    Output = Self>
		+ Shr<   u32,    Output = Self>
		+ Shr<   u64,    Output = Self>
		+ Shr<   u128,   Output = Self>
		+ Shr<   usize,  Output = Self>
		+ Shr<   i8,     Output = Self>
		+ Shr<   i16,    Output = Self>
		+ Shr<   i32,    Output = Self>
		+ Shr<   i64,    Output = Self>
		+ Shr<   i128,   Output = Self>
		+ Shr<   isize,  Output = Self>
		+ Sub<           Output = Self>
		// Assigning arithmetic operators:
		+ AddAssign
		+ BitAndAssign
		+ BitOrAssign
		+ BitXorAssign
		+ DivAssign
		+ MulAssign
		+ RemAssign
		+ ShlAssign
		+ ShlAssign<u8>
		+ ShlAssign<u16>
		+ ShlAssign<u32>
		+ ShlAssign<u64>
		+ ShlAssign<u128>
		+ ShlAssign<usize>
		+ ShlAssign<i8>
		+ ShlAssign<i16>
		+ ShlAssign<i32>
		+ ShlAssign<i64>
		+ ShlAssign<i128>
		+ ShlAssign<isize>
		+ ShrAssign
		+ ShrAssign<u8>
		+ ShrAssign<u16>
		+ ShrAssign<u32>
		+ ShrAssign<u64>
		+ ShrAssign<u128>
		+ ShrAssign<usize>
		+ ShrAssign<i8>
		+ ShrAssign<i16>
		+ ShrAssign<i32>
		+ ShrAssign<i64>
		+ ShrAssign<i128>
		+ ShrAssign<isize>
		+ SubAssign,
{
	/// The equivalent, unsigned, integral type.
	type Uint: Uint<Int = Self>;

	/// The array type that represents the bytes of this type.
	type Bytes: Array<Scalar = u8>;

	/// See [`i32::BITS`].
	const BITS: u32;

	/// See [`i32::MIN`].
	const MIN: Self;

	/// See [`i32::MAX`].
	const MAX: Self;

	/// Constructs a new, signed integer from an [`i8`] value.
	#[must_use]
	fn from_i8(value: i8) -> Self;

	/// See [`i32::from_le`].
	#[must_use]
	fn from_le(value: Self) -> Self;

	/// See [`i32::from_be`].
	#[must_use]
	fn from_be(value: Self) -> Self;

	/// See [`i32::from_ne_bytes`].
	#[must_use]
	fn from_ne_bytes(bytes: Self::Bytes) -> Self;

	/// See [`i32::from_le_bytes`].
	#[must_use]
	fn from_le_bytes(bytes: Self::Bytes) -> Self;

	/// See [`i32::from_be_bytes`].
	#[must_use]
	fn from_be_bytes(bytes: Self::Bytes) -> Self;

	/// See [`i32::from_str_radix`].
	fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError>;

	/// See [`i32::div_euclid`].
	#[must_use]
	fn div_euclid(self, rhs: Self) -> Self;

	/// See [`i32::rem_euclid`].
	#[must_use]
	fn rem_euclid(self, rhs: Self) -> Self;

	/// See [`i32::rotate_left`].
	#[must_use]
	fn rotate_left(self, rhs: u32) -> Self;

	/// See [`i32::rotate_right`].
	#[must_use]
	fn rotate_right(self, rhs: u32) -> Self;

	/// See [`i32::swap_bytes`].
	#[must_use]
	fn swap_bytes(self) -> Self;

	/// See [`i32::reverse_bits`].
	#[must_use]
	fn reverse_bits(self) -> Self;

	/// See [`i32::abs`].
	#[must_use]
	fn abs(self) -> Self;

	/// See [`i32::unsigned_abs`].
	#[must_use]
	fn unsigned_abs(self) -> Self::Uint;

	/// See [`i32::pow`].
	#[must_use]
	fn pow(self, exp: u32) -> Self;

	/// See [`i32::isqrt`].
	#[must_use]
	fn isqrt(self) -> Self;

	/// See [`i32::ilog`].
	#[must_use]
	fn ilog(self, base: Self) -> u32;

	/// See [`i32::ilog2`].
	#[must_use]
	fn ilog2(self) -> u32;

	/// See [`i32::ilog10`].
	#[must_use]
	fn ilog10(self) -> u32;

	/// See [`i32::abs_diff`].
	#[must_use]
	fn abs_diff(self, rhs: Self) -> Self::Uint;

	/// See [`i32::midpoint`].
	#[must_use]
	fn midpoint(self, rhs: Self) -> Self;

	/// See [`i32::signum`].
	#[must_use]
	fn signum(self) -> Self;

	/// See [`i32::is_negative`].
	#[must_use]
	fn is_negative(self) -> bool;

	/// See [`i32::is_positive`].
	#[must_use]
	fn is_positive(self) -> bool;

	/// See [`i32::count_zeros`].
	#[must_use]
	fn count_zeros(self) -> u32;

	/// See [`i32::count_ones`].
	#[must_use]
	fn count_ones(self) -> u32;

	/// See [`i32::leading_zeros`].
	#[must_use]
	fn leading_zeros(self) -> u32;

	/// See [`i32::leading_ones`].
	#[must_use]
	fn leading_ones(self) -> u32;

	/// See [`i32::trailing_zeros`].
	#[must_use]
	fn trailing_zeros(self) -> u32;

	/// See [`i32::trailing_ones`].
	#[must_use]
	fn trailing_ones(self) -> u32;

	/// See [`i32::checked_add`].
	#[must_use]
	fn checked_add(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_add_unsigned`].
	#[must_use]
	fn checked_add_unsigned(self, rhs: Self::Uint) -> Option<Self>;

	/// See [`i32::checked_sub`].
	#[must_use]
	fn checked_sub(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_sub_unsigned`].
	#[must_use]
	fn checked_sub_unsigned(self, rhs: Self::Uint) -> Option<Self>;

	/// See [`i32::checked_mul`].
	#[must_use]
	fn checked_mul(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_div`].
	#[must_use]
	fn checked_div(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_div_euclid`].
	#[must_use]
	fn checked_div_euclid(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_rem`].
	#[must_use]
	fn checked_rem(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_rem_euclid`].
	#[must_use]
	fn checked_rem_euclid(self, rhs: Self) -> Option<Self>;

	/// See [`i32::checked_shl`].
	#[must_use]
	fn checked_shl(self, rhs: u32) -> Option<Self>;

	/// See [`i32::checked_shr`].
	#[must_use]
	fn checked_shr(self, rhs: u32) -> Option<Self>;

	/// See [`i32::checked_neg`].
	#[must_use]
	fn checked_neg(self) -> Option<Self>;

	/// See [`i32::checked_abs`].
	#[must_use]
	fn checked_abs(self) -> Option<Self>;

	/// See [`i32::checked_pow`].
	#[must_use]
	fn checked_pow(self, exp: u32) -> Option<Self>;

	/// See [`i32::checked_ilog`].
	#[must_use]
	fn checked_ilog(self, base: Self) -> Option<u32>;

	/// See [`i32::checked_ilog2`].
	#[must_use]
	fn checked_ilog2(self) -> Option<u32>;

	/// See [`i32::checked_ilog10`].
	#[must_use]
	fn checked_ilog10(self) -> Option<u32>;

	/// See [`i32::strict_add`].
	#[must_use]
	fn strict_add(self, rhs: Self) -> Self;

	/// See [`i32::strict_add_unsigned`].
	#[must_use]
	fn strict_add_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::strict_sub`].
	#[must_use]
	fn strict_sub(self, rhs: Self) -> Self;

	/// See [`i32::strict_sub_unsigned`].
	#[must_use]
	fn strict_sub_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::strict_mul`].
	#[must_use]
	fn strict_mul(self, rhs: Self) -> Self;

	/// See [`i32::strict_div`].
	#[must_use]
	fn strict_div(self, rhs: Self) -> Self;

	/// See [`i32::strict_div_euclid`].
	#[must_use]
	fn strict_div_euclid(self, rhs: Self) -> Self;

	/// See [`i32::strict_rem`].
	#[must_use]
	fn strict_rem(self, rhs: Self) -> Self;

	/// See [`i32::strict_rem_euclid`].
	#[must_use]
	fn strict_rem_euclid(self, rhs: Self) -> Self;

	/// See [`i32::strict_shl`].
	#[must_use]
	fn strict_shl(self, rhs: u32) -> Self;

	/// See [`i32::strict_shr`].
	#[must_use]
	fn strict_shr(self, rhs: u32) -> Self;

	/// See [`i32::strict_neg`].
	#[must_use]
	fn strict_neg(self) -> Self;

	/// See [`i32::strict_abs`].
	#[must_use]
	fn strict_abs(self) -> Self;

	/// See [`i32::strict_pow`].
	#[must_use]
	fn strict_pow(self, rhs: u32) -> Self;

	/// See [`i32::unchecked_add`].
	#[expect(clippy::missing_safety_doc)]
	#[must_use]
	unsafe fn unchecked_add(self, rhs: Self) -> Self;

	/// See [`i32::unchecked_sub`].
	#[expect(clippy::missing_safety_doc)]
	#[must_use]
	unsafe fn unchecked_sub(self, rhs: Self) -> Self;

	/// See [`i32::unchecked_mul`].
	#[expect(clippy::missing_safety_doc)]
	#[must_use]
	unsafe fn unchecked_mul(self, rhs: Self) -> Self;

	/// See [`i32::overflowing_add`].
	#[must_use]
	fn overflowing_add(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_add_unsigned`].
	#[must_use]
	fn overflowing_add_unsigned(self, rhs: Self::Uint) -> (Self, bool);

	/// See [`i32::overflowing_sub`].
	#[must_use]
	fn overflowing_sub(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_sub_unsigned`].
	#[must_use]
	fn overflowing_sub_unsigned(self, rhs: Self::Uint) -> (Self, bool);

	/// See [`i32::overflowing_mul`].
	#[must_use]
	fn overflowing_mul(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_div`].
	#[must_use]
	fn overflowing_div(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_div_euclid`].
	#[must_use]
	fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_rem`].
	#[must_use]
	fn overflowing_rem(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_rem_euclid`].
	#[must_use]
	fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool);

	/// See [`i32::overflowing_shl`].
	#[must_use]
	fn overflowing_shl(self, rhs: u32) -> (Self, bool);

	/// See [`i32::overflowing_shr`].
	#[must_use]
	fn overflowing_shr(self, rhs: u32) -> (Self, bool);

	/// See [`i32::overflowing_neg`].
	#[must_use]
	fn overflowing_neg(self) -> (Self, bool);

	/// See [`i32::overflowing_abs`].
	#[must_use]
	fn overflowing_abs(self) -> (Self, bool);

	/// See [`i32::overflowing_pow`].
	#[must_use]
	fn overflowing_pow(self, exp: u32) -> (Self, bool);

	/// See [`i32::wrapping_add`].
	#[must_use]
	fn wrapping_add(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_add_unsigned`].
	#[must_use]
	fn wrapping_add_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::wrapping_sub`].
	#[must_use]
	fn wrapping_sub(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_sub_unsigned`].
	#[must_use]
	fn wrapping_sub_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::wrapping_mul`].
	#[must_use]
	fn wrapping_mul(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_div`].
	#[must_use]
	fn wrapping_div(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_div_euclid`].
	#[must_use]
	fn wrapping_div_euclid(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_rem`].
	#[must_use]
	fn wrapping_rem(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_rem_euclid`].
	#[must_use]
	fn wrapping_rem_euclid(self, rhs: Self) -> Self;

	/// See [`i32::wrapping_shl`].
	#[must_use]
	fn wrapping_shl(self, rhs: u32) -> Self;

	/// See [`i32::wrapping_shr`].
	#[must_use]
	fn wrapping_shr(self, rhs: u32) -> Self;

	/// See [`i32::wrapping_neg`].
	#[must_use]
	fn wrapping_neg(self) -> Self;

	/// See [`i32::wrapping_pow`].
	#[must_use]
	fn wrapping_pow(self, exp: u32) -> Self;

	/// See [`i32::saturating_add`].
	#[must_use]
	fn saturating_add(self, rhs: Self) -> Self;

	/// See [`i32::saturating_add_unsigned`].
	#[must_use]
	fn saturating_add_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::saturating_sub`].
	#[must_use]
	fn saturating_sub(self, rhs: Self) -> Self;

	/// See [`i32::saturating_sub_unsigned`].
	#[must_use]
	fn saturating_sub_unsigned(self, rhs: Self::Uint) -> Self;

	/// See [`i32::saturating_mul`].
	#[must_use]
	fn saturating_mul(self, rhs: Self) -> Self;

	/// See [`i32::saturating_div`].
	#[must_use]
	fn saturating_div(self, rhs: Self) -> Self;

	/// See [`i32::saturating_neg`].
	#[must_use]
	fn saturating_neg(self) -> Self;

	/// See [`i32::saturating_abs`].
	#[must_use]
	fn saturating_abs(self) -> Self;

	/// See [`i32::saturating_pow`].
	#[must_use]
	fn saturating_pow(self, exp: u32) -> Self;

	/// See [`i32::unbounded_shl`].
	#[must_use]
	fn unbounded_shl(self, rhs: u32) -> Self;

	/// See [`i32::unbounded_shr`].
	#[must_use]
	fn unbounded_shr(self, rhs: u32) -> Self;

	/// Reinterprets `self` as an unsigned integer.
	#[must_use]
	fn cast_unsigned(self) -> Self::Uint;

	/// See [`i32::to_le`].
	#[must_use]
	fn to_le(self) -> Self;

	/// See [`i32::to_be`].
	#[must_use]
	fn to_be(self) -> Self;

	/// See [`i32::to_ne_bytes`].
	#[must_use]
	fn to_ne_bytes(self) -> Self::Bytes;

	/// See [`i32::to_le_bytes`].
	#[must_use]
	fn to_le_bytes(self) -> Self::Bytes;

	/// See [`i32::to_be_bytes`].
	#[must_use]
	fn to_be_bytes(self) -> Self::Bytes;
}

macro_rules! impl_int {
	{
		$($Ty:ty { Uint = $Uint:ty, Bytes = $Bytes:ty$(,)? }),*$(,)?
	} => {$(
		impl ::multitype::SealedInt for $Ty { }

		unsafe impl ::multitype::Int for $Ty {
			type Uint = $Uint;

			type Bytes = $Bytes;

			const MIN: Self = Self::MIN;
			const MAX: Self = Self::MAX;

			const BITS: ::core::primitive::u32 = Self::BITS;

			#[inline(always)]
			#[track_caller]
			fn from_i8(value: ::core::primitive::i8) -> Self {
				value.into()
			}

			#[inline(always)]
			#[track_caller]
			fn from_le(value: Self) -> Self {
				Self::from_le(value)
			}

			#[inline(always)]
			#[track_caller]
			fn from_be(value: Self) -> Self {
				Self::from_be(value)
			}

			#[inline(always)]
			#[track_caller]
			fn from_ne_bytes(bytes: Self::Bytes) -> Self {
				Self::from_ne_bytes(bytes)
			}

			#[inline(always)]
			#[track_caller]
			fn from_le_bytes(bytes: Self::Bytes) -> Self {
				Self::from_le_bytes(bytes)
			}

			#[inline(always)]
			#[track_caller]
			fn from_be_bytes(bytes: Self::Bytes) -> Self {
				Self::from_be_bytes(bytes)
			}

			#[inline(always)]
			#[track_caller]
			fn from_str_radix(s: &str, radix: ::core::primitive::u32) -> ::core::result::Result<Self, ::core::num::ParseIntError> {
				Self::from_str_radix(s, radix)
			}

			#[inline(always)]
			#[track_caller]
			fn div_euclid(self, rhs: Self) -> Self {
				self.div_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn rem_euclid(self, rhs: Self) -> Self {
				self.rem_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn rotate_left(self, rhs: ::core::primitive::u32) -> Self {
				self.rotate_left(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn rotate_right(self, rhs: ::core::primitive::u32) -> Self {
				self.rotate_right(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn swap_bytes(self) -> Self {
				self.swap_bytes()
			}

			#[inline(always)]
			#[track_caller]
			fn reverse_bits(self) -> Self {
				self.reverse_bits()
			}

			#[inline(always)]
			#[track_caller]
			fn abs(self) -> Self {
				self.abs()
			}

			#[inline(always)]
			#[track_caller]
			fn unsigned_abs(self) -> Self::Uint {
				self.unsigned_abs()
			}

			#[inline(always)]
			#[track_caller]
			fn pow(self, exp: ::core::primitive::u32) -> Self {
				self.pow(exp)
			}

			#[inline(always)]
			#[track_caller]
			fn isqrt(self) -> Self {
				self.isqrt()
			}

			#[inline(always)]
			#[track_caller]
			fn ilog(self, base: Self) -> ::core::primitive::u32 {
				self.ilog(base)
			}

			#[inline(always)]
			#[track_caller]
			fn ilog2(self) -> ::core::primitive::u32 {
				self.ilog2()
			}

			#[inline(always)]
			#[track_caller]
			fn ilog10(self) -> ::core::primitive::u32 {
				self.ilog10()
			}

			#[inline(always)]
			#[track_caller]
			fn abs_diff(self, rhs: Self) -> Self::Uint {
				self.abs_diff(rhs)
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn midpoint(self, rhs: Self) -> Self {
				self ^ rhs >> 0x1 + self & rhs
			}

			#[inline(always)]
			#[track_caller]
			fn signum(self) -> Self {
				self.signum()
			}

			#[inline(always)]
			#[track_caller]
			fn is_negative(self) -> ::core::primitive::bool {
				self.is_negative()
			}

			#[inline(always)]
			#[track_caller]
			fn is_positive(self) -> ::core::primitive::bool {
				self.is_positive()
			}

			#[inline(always)]
			#[track_caller]
			fn count_zeros(self) -> ::core::primitive::u32 {
				self.count_zeros()
			}

			#[inline(always)]
			#[track_caller]
			fn count_ones(self) -> ::core::primitive::u32 {
				self.count_ones()
			}

			#[inline(always)]
			#[track_caller]
			fn leading_zeros(self) -> ::core::primitive::u32 {
				self.leading_zeros()
			}

			#[inline(always)]
			#[track_caller]
			fn leading_ones(self) -> ::core::primitive::u32 {
				self.leading_ones()
			}

			#[inline(always)]
			#[track_caller]
			fn trailing_zeros(self) -> ::core::primitive::u32 {
				self.trailing_zeros()
			}

			#[inline(always)]
			#[track_caller]
			fn trailing_ones(self) -> ::core::primitive::u32 {
				self.trailing_ones()
			}

			#[inline(always)]
			#[track_caller]
			fn checked_add(self, rhs: Self) -> ::core::option::Option<Self> {
				self.checked_add(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_add_unsigned(self, rhs: Self::Uint) -> ::core::option::Option<Self> {
				self.checked_add_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_sub(self, rhs: Self) -> ::core::option::Option<Self> {
				self.checked_sub(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_sub_unsigned(self, rhs: Self::Uint) -> ::core::option::Option<Self> {
				self.checked_sub_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_mul(self, rhs: Self) -> ::core::option::Option<Self> {
				self.checked_mul(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_div(self, rhs: Self) -> ::core::option::Option<Self> {
				self.checked_div(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
				self.checked_div_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_rem(self, rhs: Self) -> ::core::option::Option<Self> {
				self.checked_rem(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
				self.checked_rem_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_shl(self, rhs: ::core::primitive::u32) -> ::core::option::Option<Self> {
				self.checked_shl(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_shr(self, rhs: ::core::primitive::u32) -> ::core::option::Option<Self> {
				self.checked_shr(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_neg(self) -> ::core::option::Option<Self> {
				self.checked_neg()
			}

			#[inline(always)]
			#[track_caller]
			fn checked_abs(self) -> ::core::option::Option<Self> {
				self.checked_abs()
			}

			#[inline(always)]
			#[track_caller]
			fn checked_pow(self, exp: ::core::primitive::u32) -> ::core::option::Option<Self> {
				self.checked_pow(exp)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_ilog(self, base: Self) -> ::core::option::Option<::core::primitive::u32> {
				self.checked_ilog(base)
			}

			#[inline(always)]
			#[track_caller]
			fn checked_ilog2(self) -> ::core::option::Option<::core::primitive::u32> {
				self.checked_ilog2()
			}

			#[inline(always)]
			#[track_caller]
			fn checked_ilog10(self) -> ::core::option::Option<::core::primitive::u32> {
				self.checked_ilog10()
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_add(self, rhs: Self) -> Self {
				self.checked_add(rhs).expect("attempt to add with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_add_unsigned(self, rhs: Self::Uint) -> Self {
				self.checked_add_unsigned(rhs).expect("attempt to add with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_sub(self, rhs: Self) -> Self {
				self.checked_sub(rhs).expect("attempt to subtract with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_sub_unsigned(self, rhs: Self::Uint) -> Self {
				self.checked_sub_unsigned(rhs).expect("attempt to subtract with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_mul(self, rhs: Self) -> Self {
				self.checked_mul(rhs).expect("attempt to multiply with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_div(self, rhs: Self) -> Self {
				self.checked_div(rhs).expect("attempt to divide with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_div_euclid(self, rhs: Self) -> Self {
				self.checked_div_euclid(rhs).expect("attempt to divide with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_rem(self, rhs: Self) -> Self {
				self.checked_rem(rhs).expect("attempt to calculate the remainder with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_rem_euclid(self, rhs: Self) -> Self {
				self.checked_rem_euclid(rhs).expect("attempt to calculate the remainder with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_shl(self, rhs: ::core::primitive::u32) -> Self {
				self.checked_shl(rhs).expect("attempt to shift left with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_shr(self, rhs: ::core::primitive::u32) -> Self {
				self.checked_shr(rhs).expect("attempt to shift right with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_neg(self) -> Self {
				self.checked_neg().expect("attempt to negate with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_abs(self) -> Self {
				self.checked_abs().expect("attempt to negate with overflow")
			}

			// FIXME(backport)
			#[inline]
			#[track_caller]
			fn strict_pow(self, exp: ::core::primitive::u32) -> Self {
				self.checked_pow(exp).expect("attempt to multiply with overflow")
			}

			#[inline(always)]
			#[track_caller]
			unsafe fn unchecked_add(self, rhs: Self) -> Self {
				unsafe { self.unchecked_add(rhs) }
			}

			#[inline(always)]
			#[track_caller]
			unsafe fn unchecked_sub(self, rhs: Self) -> Self {
				unsafe { self.unchecked_sub(rhs) }
			}

			#[inline(always)]
			#[track_caller]
			unsafe fn unchecked_mul(self, rhs: Self) -> Self {
				unsafe { self.unchecked_mul(rhs) }
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_add(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_add(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_add_unsigned(self, rhs: Self::Uint) -> (Self, ::core::primitive::bool) {
				self.overflowing_add_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_sub(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_sub(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_sub_unsigned(self, rhs: Self::Uint) -> (Self, ::core::primitive::bool) {
				self.overflowing_sub_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_mul(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_mul(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_div(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_div(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_div_euclid(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_div_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_rem(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_rem(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_rem_euclid(self, rhs: Self) -> (Self, ::core::primitive::bool) {
				self.overflowing_rem_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_shl(self, rhs: ::core::primitive::u32) -> (Self, ::core::primitive::bool) {
				self.overflowing_shl(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_shr(self, rhs: ::core::primitive::u32) -> (Self, ::core::primitive::bool) {
				self.overflowing_shr(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_neg(self) -> (Self, ::core::primitive::bool) {
				self.overflowing_neg()
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_abs(self) -> (Self, ::core::primitive::bool) {
				self.overflowing_abs()
			}

			#[inline(always)]
			#[track_caller]
			fn overflowing_pow(self, exp: ::core::primitive::u32) -> (Self, ::core::primitive::bool) {
				self.overflowing_pow(exp)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_add(self, rhs: Self) -> Self {
				self.wrapping_add(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_add_unsigned(self, rhs: Self::Uint) -> Self {
				self.wrapping_add_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_sub(self, rhs: Self) -> Self {
				self.wrapping_sub(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_sub_unsigned(self, rhs: Self::Uint) -> Self {
				self.wrapping_sub_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_mul(self, rhs: Self) -> Self {
				self.wrapping_mul(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_div(self, rhs: Self) -> Self {
				self.wrapping_div(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_div_euclid(self, rhs: Self) -> Self {
				self.wrapping_div_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_rem(self, rhs: Self) -> Self {
				self.wrapping_rem(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_rem_euclid(self, rhs: Self) -> Self {
				self.wrapping_rem_euclid(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_shl(self, rhs: ::core::primitive::u32) -> Self {
				self.wrapping_shl(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_shr(self, rhs: ::core::primitive::u32) -> Self {
				self.wrapping_shr(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_neg(self) -> Self {
				self.wrapping_neg()
			}

			#[inline(always)]
			#[track_caller]
			fn wrapping_pow(self, exp: ::core::primitive::u32) -> Self {
				self.wrapping_pow(exp)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_add(self, rhs: Self) -> Self {
				self.saturating_add(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_add_unsigned(self, rhs: Self::Uint) -> Self {
				self.saturating_add_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_sub(self, rhs: Self) -> Self {
				self.saturating_sub(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_sub_unsigned(self, rhs: Self::Uint) -> Self {
				self.saturating_sub_unsigned(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_mul(self, rhs: Self) -> Self {
				self.saturating_mul(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_div(self, rhs: Self) -> Self {
				self.saturating_div(rhs)
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_neg(self) -> Self {
				self.saturating_neg()
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_abs(self) -> Self {
				self.saturating_abs()
			}

			#[inline(always)]
			#[track_caller]
			fn saturating_pow(self, exp: ::core::primitive::u32) -> Self {
				self.saturating_pow(exp)
			}

			// FIXME(backport)
			#[inline]
			fn unbounded_shl(self, rhs: ::core::primitive::u32) -> Self {
				if rhs < Self::BITS {
					self << rhs
				} else {
					0x0
				}
			}

			// FIXME(backport)
			#[inline]
			fn unbounded_shr(self, rhs: ::core::primitive::u32) -> Self {
				if rhs < Self::BITS {
					self >> rhs
				} else {
					0x0
				}
			}

			// FIXME(backport)
			#[inline(always)]
			fn cast_unsigned(self) -> Self::Uint {
				self as Self::Uint
			}

			#[inline(always)]
			#[track_caller]
			fn to_le(self) -> Self {
				self.to_le()
			}

			#[inline(always)]
			#[track_caller]
			fn to_be(self) -> Self {
				self.to_be()
			}

			#[inline(always)]
			#[track_caller]
			fn to_ne_bytes(self) -> Self::Bytes {
				self.to_ne_bytes()
			}

			#[inline(always)]
			#[track_caller]
			fn to_le_bytes(self) -> Self::Bytes {
				self.to_le_bytes()
			}

			#[inline(always)]
			#[track_caller]
			fn to_be_bytes(self) -> Self::Bytes {
				self.to_be_bytes()
			}
		}
	)*};
}

impl_int! {
	i8   { Uint = u8,   Bytes = [u8; 0x01] },
	i16  { Uint = u16,  Bytes = [u8; 0x02] },
	i32  { Uint = u32,  Bytes = [u8; 0x04] },
	i64  { Uint = u64,  Bytes = [u8; 0x08] },
	i128 { Uint = u128, Bytes = [u8; 0x10] },
}

#[cfg(target_pointer_width = "16")]
impl_int! {
	isize { Uint = usize, Bytes = [u8; 0x2] },
}

#[cfg(target_pointer_width = "32")]
impl_int! {
	isize { Uint = usize, Bytes = [u8; 0x4] },
}

#[cfg(target_pointer_width = "64")]
impl_int! {
	isize { Uint = usize, Bytes = [u8; 0x8] },
}
