//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Generic type checking
/// </summary>
public static class gtype_check {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type TypeOf<TComparand>( Type type ) =>
   TypeOf( type, typeof(TComparand) );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type TypeOf( Type type, Type comparandType ) =>
   u.type.IsTypeOf( type, comparandType ) ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT( comparandType );

//==================================================================================================

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type ByRef( Type type ) =>
   type.IsByRef ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_REFERENCE_TYPE( type );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type ValueType( Type type ) =>
   type.IsValueType ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_VALUE_TYPE( type );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type Enum( Type type ) =>
   Enum( type, null );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type Enum( Type type, bool? flagsEnumerationRestriction )
{
   if ( !type.IsEnum )
      throw gtype_check_errors.GENTYPE_IS_NOT_ENUMERATION( type );
   if ( flagsEnumerationRestriction.HasValue &&
        flagsEnumerationRestriction.Value != u.enum_val.IsFlagsEnumeration( type ) )
      throw flagsEnumerationRestriction.Value ?
         gtype_check_errors.GENTYPE_IS_NOT_FLAGS_ENUMERATION( type ) :
         gtype_check_errors.GENTYPE_IS_NOT_NONFLAGS_ENUM( type );
   return type;
}

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type FlagsEnum( Type type ) =>
   Enum( type, true );

//--------------------------------------------------------------------------------------------------

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type StdValueType( Type type ) =>
   u.type.IsStdValue( type ) ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_STD_VALUE_TYPE( type );

//--------------------------------------------------------------------------------------------------

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type IntegralNumber( Type type ) =>
   u.type.IsIntegralNumber( type ) ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_INTEGRAL_TYPE( type );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type IntegralSignedlNumber( Type type ) =>
   u.type.IsIntegralSignedNumber( type ) ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_INTEGRAL_SIGNED_NUMBER_TYPE( type );

/// <exception cref="EGenericType" />
[u.returns_source]
public static Type IntegralUnsignedNumber( Type type ) =>
   u.type.IsIntegralUnsignedNumber( type ) ? type :
      throw gtype_check_errors.GENTYPE_IS_NOT_INTEGRAL_UNSIGNED_NUMBER_TYPE( type );

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // gtype_check

} // user_rtx (.wasm)
