// Copyright 2025 Gabriel Bjørnager Jensen.

mod seal {
	pub trait Int { }
}

use crate::{Array, Uint};

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,
	Rem,
	RemAssign,
	Shl,
	ShlAssign,
	Shr,
	ShrAssign,
	Sub,
	SubAssign,
};

pub(crate) use seal::Int as SealedInt;

/// 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.
///
/// # Safety
///
/// [`Unsigned`](Self::Unsigned) 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:
		SealedInt
		+ Binary
		+ Copy
		+ Debug
		+ Default
		+ Display
		+ Eq
		+ LowerExp
		+ LowerHex
		+ Octal
		+ Ord
		+ PartialEq
		+ PartialOrd
		+ Product
		+ Sum
		+ UpperExp
		+ UpperHex
		// Operators:
		+ Add<   Output = Self>
		+ BitAnd<Output = Self>
		+ BitOr< Output = Self>
		+ BitXor<Output = Self>
		+ Div<   Output = Self>
		+ Mul<   Output = Self>
		+ Neg<   Output = Self>
		+ Rem<   Output = Self>
		+ Shl<   Output = Self>
		+ Shr<   Output = Self>
		+ Sub<   Output = Self>
		// Assignement operators:
		+ AddAssign
		+ BitAndAssign
		+ BitOrAssign
		+ BitXorAssign
		+ DivAssign
		+ MulAssign
		+ RemAssign
		+ ShlAssign
		+ ShrAssign
		+ SubAssign,
{
	/// The equivalent, unsigned, integral type.
	type Unsigned: Uint;

	/// 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 signed integer from an [`i8`] value.
	#[must_use]
	fn from_i8(value: i8) -> Self;

	/// Unsafely constructs an unsigned integer from an [`i16`] value.
	///
	/// This constructor should not be used directly; instead, use [`Least16::from_i16`](crate::Least16::from_i16) when possible.
	///
	/// # Safety
	///
	/// The value of `value` must not exceed [`MAX`](Self::MAX).
	#[must_use]
	unsafe fn from_i16_unchecked(value: i16) -> Self;

	/// Unsafely constructs an unsigned integer from an [`i32`] value.
	///
	/// This constructor should not be used directly; instead, use [`Least32::from_i32`](crate::Least32::from_i32) when possible.
	///
	/// # Safety
	///
	/// The value of `value` must not exceed [`MAX`](Self::MAX).
	#[must_use]
	unsafe fn from_i32_unchecked(value: i32) -> Self;

	/// Unsafely constructs an unsigned integer from an [`i64`] value.
	///
	/// This constructor should not be used directly; instead, use [`Least64::from_i64`](crate::Least64::from_i64) when possible.
	///
	/// # Safety
	///
	/// The value of `value` must not exceed [`MAX`](Self::MAX).
	#[must_use]
	unsafe fn from_i64_unchecked(value: i64) -> Self;

	/// Unsafely constructs an unsigned integer from an [`i128`] value.
	///
	/// This constructor should not be used directly; instead, use [`Least128::from_i128`](crate::Least128::from_i128) when possible.
	///
	/// # Safety
	///
	/// The value of `value` must not exceed [`MAX`](Self::MAX).
	#[must_use]
	unsafe fn from_i128_unchecked(value: i128) -> 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::Unsigned;

	/// 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::Unsigned;

	/// 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> (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::Unsigned) -> (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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned;

	/// 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 { Unsigned = $signed:ty, Bytes = $bytes:ty$(,)? }),*$(,)?
	} => {
		$(
			impl ::multitype::SealedInt for $ty { }

			unsafe impl ::multitype::Int for $ty {
				type Unsigned = $signed;

				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()
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				#[track_caller]
				unsafe fn from_i16_unchecked(value: ::core::primitive::i16) -> Self {
					::core::debug_assert!(
						Self::try_from(value).is_ok(),
						"cannot construct `{}` object with value `{value}`",
						::core::stringify!($ty),
					);

					value as Self
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				#[track_caller]
				unsafe fn from_i32_unchecked(value: ::core::primitive::i32) -> Self {
					::core::debug_assert!(
						Self::try_from(value).is_ok(),
						"cannot construct `{}` object with value `{value}`",
						::core::stringify!($ty),
					);

					value as Self
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				#[track_caller]
				unsafe fn from_i64_unchecked(value: ::core::primitive::i64) -> Self {
					::core::debug_assert!(
						Self::try_from(value).is_ok(),
						"cannot construct `{}` object with value `{value}`",
						::core::stringify!($ty),
					);

					value as Self
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				#[track_caller]
				unsafe fn from_i128_unchecked(value: ::core::primitive::i128) -> Self {
					::core::debug_assert!(
						Self::try_from(value).is_ok(),
						"cannot construct `{}` object with value `{value}`",
						::core::stringify!($ty),
					);

					value as Self
				}

				#[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::Unsigned {
					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::Unsigned {
					self.abs_diff(rhs)
				}

				#[inline(always)]
				#[track_caller]
				fn midpoint(self, rhs: Self) -> Self {
					self.midpoint(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::Unsigned) -> ::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::Unsigned) -> ::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()
				}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

				#[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::Unsigned) -> (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::Unsigned) -> (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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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::Unsigned) -> 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)
				}

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

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

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

				#[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    { Unsigned = u8,   Bytes = [u8; 0x01] },
	i16   { Unsigned = u16,  Bytes = [u8; 0x02] },
	i32   { Unsigned = u32,  Bytes = [u8; 0x04] },
	i64   { Unsigned = u64,  Bytes = [u8; 0x08] },
	i128  { Unsigned = u128, Bytes = [u8; 0x10] },
}

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

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

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