// Copyright 2025 Gabriel Bjørnager Jensen.

use crate::Float;

macro_rules! def_float_leasts {
	{$(
		$Ident:ident {
			seal:       $Seal:path,
			extends:    $Extends:path,
			float:      $Float:ty,
			uint:       $Uint:ty,
			int:        $Int:ty,
			float_ctor: $float_ctor:ident,
			uint_ctor:  $uint_ctor:ident,
			int_ctor:   $int_ctor:ident$(,)?
		} for {
			$($Ty:ty $(= $ty_feature:literal,)?),*$(,)?
		}
	)*} => {$(
		#[doc = ::core::concat!(
			"Denotes a floating-pointer number that is at least as wide as [`",
			::core::stringify!($Float),
			"`].\n",
			"\n",
			"# Safety\n",
			"\n",
			"Only primitive, floating-point types that fit the size requirement may implement this type.\n",
		)]
		pub trait $Ident
		where
			Self:
				$Seal
				+ $Extends
				+ ::core::convert::From<$Float>
				+ ::core::convert::From<$Uint>
				+ ::core::convert::From<$Int>,
		{
			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from an [`",
				::core::stringify!($Float),
				"`] value.\n",
			)]
			#[must_use]
			fn $float_ctor(value: $Float) -> Self;

			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from a [`",
				::core::stringify!($Uint),
				"`] value.\n",
			)]
			#[must_use]
			fn $uint_ctor(value: $Uint) -> Self;

			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from an [`",
				::core::stringify!($Int),
				"`] value.\n",
			)]
			#[must_use]
			fn $int_ctor(value: $Int) -> Self;
		}

		$(
			$(#[cfg(feature = $ty_feature)])?
			impl $Seal for $Ty { }

			$(
				#[cfg(feature = $ty_feature)]
				#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $ty_feature)))]
			)?
			impl $Ident for $Ty {
				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				fn $float_ctor(value: $Float) -> Self {
					value as Self
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				fn $uint_ctor(value: $Uint) -> Self {
					value as Self
				}

				#[inline(always)]
				#[allow(clippy::cast_lossless)]
				fn $int_ctor(value: $Int) -> Self {
					value as Self
				}
			}
		)*
	)*};
}

macro_rules! def_locked_float_leasts {
	{$(
		$Ident:ident {
			feature:    $feature:literal,
			seal:       $Seal:path,
			extends:    $Extends:path,
			float:      $Float:ty,
			uint:       $Uint:ty,
			int:        $Int:ty,
			float_ctor: $float_ctor:ident,
			uint_ctor:  $uint_ctor:ident,
			int_ctor:   $int_ctor:ident$(,)?
		} for {
			$($Ty:ty $(= $ty_feature:literal,)?),*$(,)?
		}
	)*} => {$(
		#[doc = ::core::concat!(
			"Denotes a floating-pointer number that is at least as wide as [`",
			::core::stringify!($Float),
			"`].\n",
			"\n",
			"# Safety\n",
			"\n",
			"Only primitive, floating-point types that fit the size requirement may implement this type.\n",
		)]
		#[cfg(feature = $feature)]
		#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
		pub trait $Ident
		where
			Self:
				$Seal
				+ $Extends
				+ ::core::convert::From<$Float>
				+ ::core::convert::From<$Uint>
				+ ::core::convert::From<$Int>,
		{
			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from an [`",
				::core::stringify!($Float),
				"`] value.\n",
			)]
			#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
			#[must_use]
			fn $float_ctor(value: $Float) -> Self;

			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from a [`",
				::core::stringify!($Uint),
				"`] value.\n",
			)]
			#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
			#[must_use]
			fn $uint_ctor(value: $Uint) -> Self;

			#[doc = ::core::concat!(
				"Constructs a new, floating-point number from an [`",
				::core::stringify!($Int),
				"`] value.\n",
			)]
			#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
			#[must_use]
			fn $int_ctor(value: $Int) -> Self;
		}

		$(
			#[cfg(feature = $feature)]
			$(#[cfg(feature = $ty_feature)])?
			impl $Seal for $Ty { }

			#[cfg(feature = $feature)]
			#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $feature)))]
			$(
				#[cfg(feature = $ty_feature)]
				#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = $ty_feature)))]
			)?
			impl $Ident for $Ty {
				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				fn $float_ctor(value: $Float) -> Self {
					value as Self
				}

				#[allow(clippy::cast_lossless)]
				#[inline(always)]
				fn $uint_ctor(value: $Uint) -> Self {
					value as Self
				}

				#[inline(always)]
				#[allow(clippy::cast_lossless)]
				fn $int_ctor(value: $Int) -> Self {
					value as Self
				}
			}
		)*
	)*};
}

def_float_leasts! {
	FloatLeast32 {
		seal:       crate::SealedFloatLeast32,
		extends:    Float,
		float:      f32,
		uint:       u16,
		int:        i16,
		float_ctor: from_f32,
		uint_ctor:  from_u16,
		int_ctor:   from_i16,
	} for {
		f32,
		f64,
		f128 = "f128",
	}
}

def_locked_float_leasts! {
	FloatLeast64 {
		feature:    "f128",
		seal:       crate::SealedFloatLeast64,
		extends:    FloatLeast32,
		float:      f64,
		uint:       u32,
		int:        i32,
		float_ctor: from_f64,
		uint_ctor:  from_u32,
		int_ctor:   from_i32,
	} for {
		f64,
		f128 = "f128",
	}
}
