// Copyright 2025 Gabriel Bjørnager Jensen.

mod test;

mod seal {
	macro_rules! def_sealed_least {
		{
			$( $ident:ident for {
				$($ty:ty $(= $feature:literal)?),*$(,)?
			} )*
		} => {
			$(
				pub trait $ident { }

				$(
					$(
						#[cfg(feature = $feature)]
					)?
					impl $ident for $ty { }
				)*
			)*
		};
	}

	def_sealed_least! {
		SealedLeast16 for {
			u16,
			u32,
			u64,
			u128,
			usize,

			i16,
			i32,
			i64,
			i128,
			isize,

			f16  = "f16",
			f32,
			f64,
			f128 = "f128",
		}

		SealedLeast32 for {
			u32,
			u64,
			u128,

			i32,
			i64,
			i128,

			f32,
			f64,
			f128 = "f128",
		}

		SealedLeast64 for {
			u64,
			u128,

			i64,
			i128,

			f64,
			f128 = "f128",
		}

		SealedLeast128 for {
			u128,

			i128,

			f128 = "f128",
		}
	}
}

pub(crate) use seal::*;

macro_rules! def_least {
	{
		$( $ident:ident {
			seal:             $seal:path,
			$(extends:          $extends:path,)?
			uint:             $uint:ty,
			int:              $int:ty,
			uint_ctor:        $uint_ctor:ident,
			int_ctor:         $int_ctor:ident,
			unsafe_uint_ctor: $unsafe_uint_ctor:ident,
			unsafe_int_ctor:  $unsafe_int_ctor:ident,
			pretty_width:     $pretty_width:literal$(,)?
		} for {
			$($ty:ty $(= $feature:literal)?),*$(,)?
		} )*
	} => {$(
		#[doc = ::core::concat!(
			"Denotes a primitive type of at least ",
			$pretty_width,
			" bit(s).\n",
			"\n",
			"# Safety\n",
			"\n",
			"Only primitive type that fit the size requirement may implement this type.\n",
		)]
		pub unsafe trait $ident: Copy + $seal $(+ $extends)? {
			#[doc = ::core::concat!(
				"Constructs a new object from an [`",
				::core::stringify!($uint),
				"`] value.\n",
				"\n",
				"The provided value will be zero-padded to the width of the destination type.\n",
			)]
			#[inline(always)]
			#[must_use]
			fn $uint_ctor(value: $uint) -> Self
			where
				Self: ::multitype::Uint,
			{
				unsafe { Self::$unsafe_uint_ctor(value) }
			}

			#[doc = ::core::concat!(
				"Constructs a new object from an [`",
				::core::stringify!($int),
				"`] value.\n",
				"\n",
				"The provided value will be sign-padded to the width of the destination type.\n",
			)]
			#[inline(always)]
			#[must_use]
			fn $int_ctor(value: $int) -> Self
			where
				Self: ::multitype::Int,
			{
				unsafe { Self::$unsafe_int_ctor(value) }
			}
		}

		$(
			$(
				#[cfg(feature = $feature)]
				#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
			)?
			unsafe impl $ident for $ty { }
		)*
	)*};
}

def_least! {
	Least16 {
		seal:             SealedLeast16,
		uint:             u16,
		int:              i16,
		uint_ctor:        from_u16,
		int_ctor:         from_i16,
		unsafe_uint_ctor: from_u16_unchecked,
		unsafe_int_ctor:  from_i16_unchecked,
		pretty_width:     "16",
	} for {
		u16,
		u32,
		u64,
		u128,
		usize,

		i16,
		i32,
		i64,
		i128,
		isize,

		f16  = "f16",
		f32,
		f64,
		f128 = "f128",
	}

	Least32 {
		seal:             SealedLeast32,
		extends:          Least16,
		uint:             u32,
		int:              i32,
		uint_ctor:        from_u32,
		int_ctor:         from_i32,
		unsafe_uint_ctor: from_u32_unchecked,
		unsafe_int_ctor:  from_i32_unchecked,
		pretty_width:     "32",
	} for {
		u32,
		u64,
		u128,

		i32,
		i64,
		i128,

		f32,
		f64,
		f128 = "f128",
	}

	Least64 {
		seal:             SealedLeast64,
		extends:          Least32,
		uint:             u64,
		int:              i64,
		uint_ctor:        from_u64,
		int_ctor:         from_i64,
		unsafe_uint_ctor: from_u64_unchecked,
		unsafe_int_ctor:  from_i64_unchecked,
		pretty_width:     "64",
	} for {
		u64,
		u128,

		i64,
		i128,

		f64,
		f128 = "f128",
	}

	Least128 {
		seal:             SealedLeast128,
		extends:          Least64,
		uint:             u128,
		int:              i128,
		uint_ctor:        from_u128,
		int_ctor:         from_i128,
		unsafe_uint_ctor: from_u128_unchecked,
		unsafe_int_ctor:  from_i128_unchecked,
		pretty_width    : "128",
	} for {
		u128,

		i128,

		f128 = "f128",
	}
}
