diff --git a/1.3/Assemblies/1Fishery.dll b/1.3/Assemblies/1Fishery.dll new file mode 100644 index 0000000..a26c4b7 Binary files /dev/null and b/1.3/Assemblies/1Fishery.dll differ diff --git a/1.3/Assemblies/IndexRange.dll b/1.3/Assemblies/IndexRange.dll new file mode 100644 index 0000000..be06f22 Binary files /dev/null and b/1.3/Assemblies/IndexRange.dll differ diff --git a/1.3/Assemblies/System.Runtime.CompilerServices.Unsafe.dll b/1.3/Assemblies/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000..c5ba4e4 Binary files /dev/null and b/1.3/Assemblies/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/1.4/Assemblies/1Fishery.dll b/1.4/Assemblies/1Fishery.dll new file mode 100644 index 0000000..46ac14d Binary files /dev/null and b/1.4/Assemblies/1Fishery.dll differ diff --git a/1.4/Assemblies/IndexRange.dll b/1.4/Assemblies/IndexRange.dll new file mode 100644 index 0000000..be06f22 Binary files /dev/null and b/1.4/Assemblies/IndexRange.dll differ diff --git a/1.4/Assemblies/System.Runtime.CompilerServices.Unsafe.dll b/1.4/Assemblies/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000..c5ba4e4 Binary files /dev/null and b/1.4/Assemblies/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/About/About.xml b/About/About.xml new file mode 100644 index 0000000..d71e95d --- /dev/null +++ b/About/About.xml @@ -0,0 +1,28 @@ + + + Fishery - Modding Library + bs.fishery + +
  • 1.3
  • +
  • 1.4
  • +
    + bradson + https://github.com/bbradson/fishery + +
  • Ludeon.RimWorld
  • +
  • me.samboycoding.betterloading
  • +
  • zetrith.prepatcher
  • +
    + +
  • brrainz.harmony
  • +
    + +
  • + brrainz.harmony + Harmony + steam://url/CommunityFilePage/2009463077 + https://github.com/pardeike/HarmonyRimWorld/releases/latest +
  • +
    + Additions for Harmony to simplify otherwise complex patch operations +
    \ No newline at end of file diff --git a/LICENSE b/LICENSE index a612ad9..a7064a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,5 @@ +Copyright (c) 2022 bradson + Mozilla Public License Version 2.0 ================================== @@ -35,7 +37,7 @@ Mozilla Public License Version 2.0 means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in + means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" @@ -357,7 +359,7 @@ Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. + file, You can obtain one at https://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE @@ -370,4 +372,4 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/README.md b/README.md index 568efab..c067c6f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # Fishery - Modding Library +Modding Library for RimWorld. Used by Performance Fish. +Useful functions include various abstractions around IL in FishTranspiler, to make writing of transpilers easier and more robust. A couple collections like Dictionary and Span have extension methods for fast and convenient lookups. Some functionalities of Microsoft's Community Toolkit are included, expanded upon and modified to better fit Unity. Equality includes generic extension methods to use in place of Equals on structs without memory allocations. Convert provides a faster, generic alternative to System.Convert.ToType. FisheryLib.Reflection provides a couple reflection helpers, Aliases has a methodof function intended to be utilized with `global using static Aliases` to directly retrieve method infos from static method groups. diff --git a/Source/FisheryLib.Tests/.editorconfig b/Source/FisheryLib.Tests/.editorconfig new file mode 100644 index 0000000..6cde0c3 --- /dev/null +++ b/Source/FisheryLib.Tests/.editorconfig @@ -0,0 +1,185 @@ +[*.cs] + +file_header_template = /* Copyright (c) 2022 bradson\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */ + +# CA2211: Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:suggestion +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = when_multiline:suggestion +csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_expression_bodied_constructors = true:suggestion +csharp_style_expression_bodied_operators = true:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_accessors = true:suggestion +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:silent +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +[*.cs] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.constant_should_be_all_upper.severity = suggestion +dotnet_naming_rule.constant_should_be_all_upper.symbols = constant +dotnet_naming_rule.constant_should_be_all_upper.style = all_upper + +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.severity = suggestion +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.symbols = private_or_protected_field +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.style = camel_case_with__ + +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.severity = silent +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.symbols = public_or_internal_field +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.style = camel_case + +# Symbol specifications + +dotnet_naming_symbols.constant.applicable_kinds = field, local +dotnet_naming_symbols.constant.applicable_accessibilities = * +dotnet_naming_symbols.constant.required_modifiers = const + +dotnet_naming_symbols.private_or_protected_field.applicable_kinds = field +dotnet_naming_symbols.private_or_protected_field.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_or_protected_field.required_modifiers = + +dotnet_naming_symbols.public_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.public_or_internal_field.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_or_internal_field.required_modifiers = + +# Naming styles + +dotnet_naming_style.all_upper.required_prefix = +dotnet_naming_style.all_upper.required_suffix = +dotnet_naming_style.all_upper.word_separator = _ +dotnet_naming_style.all_upper.capitalization = all_upper + +dotnet_naming_style.camel_case_with__.required_prefix = _ +dotnet_naming_style.camel_case_with__.required_suffix = +dotnet_naming_style.camel_case_with__.word_separator = +dotnet_naming_style.camel_case_with__.capitalization = camel_case + +dotnet_naming_style.camel_case.required_prefix = +dotnet_naming_style.camel_case.required_suffix = +dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.capitalization = camel_case +dotnet_diagnostic.CA1805.severity = none +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_prefer_static_local_function = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +csharp_space_around_binary_operators = before_and_after + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_diagnostic.CA1838.severity = suggestion +dotnet_diagnostic.CA1848.severity = suggestion +dotnet_diagnostic.CA2215.severity = suggestion +dotnet_style_readonly_field = true:silent +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning +dotnet_style_allow_multiple_blank_lines_experimental = false:suggestion +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = non_public:suggestion +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion +indent_style = tab diff --git a/Source/FisheryLib.Tests/FisheryLib.Tests.csproj b/Source/FisheryLib.Tests/FisheryLib.Tests.csproj new file mode 100644 index 0000000..0843495 --- /dev/null +++ b/Source/FisheryLib.Tests/FisheryLib.Tests.csproj @@ -0,0 +1,65 @@ + + + + net48 + preview + True + preview-all + True + v1.3;v1.4 + + + + + + + E:\RimWorld\1.3\RimWorldWin64_Data\Managed\Assembly-CSharp.dll + + + E:\RimWorld\1.3\RimWorldWin64_Data\Managed\mscorlib.dll + + + E:\RimWorld\1.3\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll + + + E:\RimWorld\1.3\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll + + + ..\..\1.3\Assemblies\1Fishery.dll + + + + + + + + E:\RimWorld\1.4\RimWorldWin64_Data\Managed\Assembly-CSharp.dll + + + E:\RimWorld\1.4\RimWorldWin64_Data\Managed\mscorlib.dll + + + E:\RimWorld\1.4\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll + + + E:\RimWorld\1.4\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll + + + ..\..\1.4\Assemblies\1Fishery.dll + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + \ No newline at end of file diff --git a/Source/FisheryLib.Tests/FisheryLib.Tests.sln b/Source/FisheryLib.Tests/FisheryLib.Tests.sln new file mode 100644 index 0000000..58c484d --- /dev/null +++ b/Source/FisheryLib.Tests/FisheryLib.Tests.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32728.150 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FisheryLib.Tests", "FisheryLib.Tests.csproj", "{5BFAFA41-9B21-4EC3-B3EB-5CBF6D0A300C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + v1.3|Any CPU = v1.3|Any CPU + v1.4|Any CPU = v1.4|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5BFAFA41-9B21-4EC3-B3EB-5CBF6D0A300C}.v1.3|Any CPU.ActiveCfg = v1.3|Any CPU + {5BFAFA41-9B21-4EC3-B3EB-5CBF6D0A300C}.v1.3|Any CPU.Build.0 = v1.3|Any CPU + {5BFAFA41-9B21-4EC3-B3EB-5CBF6D0A300C}.v1.4|Any CPU.ActiveCfg = v1.4|Any CPU + {5BFAFA41-9B21-4EC3-B3EB-5CBF6D0A300C}.v1.4|Any CPU.Build.0 = v1.4|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {832FF2F6-0C42-42BD-8599-6288138CCD01} + EndGlobalSection +EndGlobal diff --git a/Source/FisheryLib.Tests/UnitTest1.cs b/Source/FisheryLib.Tests/UnitTest1.cs new file mode 100644 index 0000000..8189662 --- /dev/null +++ b/Source/FisheryLib.Tests/UnitTest1.cs @@ -0,0 +1,13 @@ +global using System; +global using Xunit; + +namespace FisheryLib.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} \ No newline at end of file diff --git a/Source/FisheryLib/.editorconfig b/Source/FisheryLib/.editorconfig new file mode 100644 index 0000000..14c2131 --- /dev/null +++ b/Source/FisheryLib/.editorconfig @@ -0,0 +1,185 @@ +[*.cs] + +file_header_template = Copyright (c) 2022 bradson\nThis Source Code Form is subject to the terms of the Mozilla Public\nLicense, v. 2.0. If a copy of the MPL was not distributed with this\nfile, You can obtain one at https://mozilla.org/MPL/2.0/. + +# CA2211: Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:suggestion +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = when_multiline:suggestion +csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_expression_bodied_constructors = true:suggestion +csharp_style_expression_bodied_operators = true:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_accessors = true:suggestion +csharp_style_expression_bodied_lambdas = true:suggestion +csharp_style_expression_bodied_local_functions = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:silent +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +[*.cs] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.constant_should_be_all_upper.severity = suggestion +dotnet_naming_rule.constant_should_be_all_upper.symbols = constant +dotnet_naming_rule.constant_should_be_all_upper.style = all_upper + +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.severity = suggestion +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.symbols = private_or_protected_field +dotnet_naming_rule.private_or_protected_field_should_be_camel_case_with__.style = camel_case_with__ + +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.severity = silent +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.symbols = public_or_internal_field +dotnet_naming_rule.public_or_internal_field_should_be_camel_case.style = camel_case + +# Symbol specifications + +dotnet_naming_symbols.constant.applicable_kinds = field, local +dotnet_naming_symbols.constant.applicable_accessibilities = * +dotnet_naming_symbols.constant.required_modifiers = const + +dotnet_naming_symbols.private_or_protected_field.applicable_kinds = field +dotnet_naming_symbols.private_or_protected_field.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_or_protected_field.required_modifiers = + +dotnet_naming_symbols.public_or_internal_field.applicable_kinds = field +dotnet_naming_symbols.public_or_internal_field.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_or_internal_field.required_modifiers = + +# Naming styles + +dotnet_naming_style.all_upper.required_prefix = +dotnet_naming_style.all_upper.required_suffix = +dotnet_naming_style.all_upper.word_separator = _ +dotnet_naming_style.all_upper.capitalization = all_upper + +dotnet_naming_style.camel_case_with__.required_prefix = _ +dotnet_naming_style.camel_case_with__.required_suffix = +dotnet_naming_style.camel_case_with__.word_separator = +dotnet_naming_style.camel_case_with__.capitalization = camel_case + +dotnet_naming_style.camel_case.required_prefix = +dotnet_naming_style.camel_case.required_suffix = +dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.capitalization = camel_case +dotnet_diagnostic.CA1805.severity = none +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_prefer_static_local_function = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:suggestion +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +csharp_space_around_binary_operators = before_and_after + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_diagnostic.CA1838.severity = suggestion +dotnet_diagnostic.CA1848.severity = suggestion +dotnet_diagnostic.CA2215.severity = suggestion +dotnet_style_readonly_field = true:silent +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning +dotnet_style_allow_multiple_blank_lines_experimental = false:suggestion +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = non_public:suggestion +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion +indent_style = tab diff --git a/Source/FisheryLib/Aliases.cs b/Source/FisheryLib/Aliases.cs new file mode 100644 index 0000000..fbaade2 --- /dev/null +++ b/Source/FisheryLib/Aliases.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +global using static FisheryLib.Aliases; +using System.Runtime.CompilerServices; + +namespace FisheryLib; + +[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "alias")] +public static class Aliases +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MethodInfo methodof(Delegate method) => method.Method; +} \ No newline at end of file diff --git a/Source/FisheryLib/ArraySortHelper.cs b/Source/FisheryLib/ArraySortHelper.cs new file mode 100644 index 0000000..7e91c41 --- /dev/null +++ b/Source/FisheryLib/ArraySortHelper.cs @@ -0,0 +1,1163 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FisheryLib; +#region ArraySortHelper for single arrays + +internal sealed class ArraySortHelper : IArraySortHelper +{ + public static IArraySortHelper Default { get; } = CreateArraySortHelper(); + + private static IArraySortHelper CreateArraySortHelper() + => typeof(IComparable).IsAssignableFrom(typeof(T)) + ? (IArraySortHelper)Activator.CreateInstance(typeof(GenericArraySortHelper<>).MakeGenericType(typeof(T))) + : new ArraySortHelper(); + + #region IArraySortHelper Members + + public void Sort(Span keys, IComparer? comparer) + { + // Add a try block here to detect IComparers (or their + // underlying IComparables, etc) that are bogus. + try + { + comparer ??= Comparer.Default; + IntrospectiveSort(keys, comparer.Compare); + } + catch (IndexOutOfRangeException) + { + SortUtils.ThrowArgumentException_BadComparer(comparer); + } + catch (Exception e) + { + ThrowHelper.ThrowInvalidOperationException(SortUtils.InvalidOperation_IComparerFailed, e); + } + } + + #endregion + + public static void Sort(Span keys, Comparison comparer) + { + Debug.Assert(comparer != null, "Check the arguments in the caller!"); + + // Add a try block here to detect bogus comparisons + try + { + IntrospectiveSort(keys, comparer!); + } + catch (IndexOutOfRangeException) + { + SortUtils.ThrowArgumentException_BadComparer(comparer); + } + catch (Exception e) + { + ThrowHelper.ThrowInvalidOperationException(SortUtils.InvalidOperation_IComparerFailed, e); + } + } + + private static void SwapIfGreater(Span keys, Comparison comparer, int i, int j) + { + Debug.Assert(i != j); + + if (comparer(keys[i], keys[j]) > 0) + { + (keys[j], keys[i]) = (keys[i], keys[j]); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(Span a, int i, int j) + { + Debug.Assert(i != j); + + (a[j], a[i]) = (a[i], a[j]); + } + + public static void IntrospectiveSort(Span keys, Comparison comparer) + { + Debug.Assert(comparer != null); + + if (keys.Length > 1) + { + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer!); + } + } + + private static void IntroSort(Span keys, int depthLimit, Comparison comparer) + { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); + Debug.Assert(comparer != null); + + var partitionSize = keys.Length; + while (partitionSize > 1) + { + if (partitionSize <= SortUtils.INTROSORT_SIZE_THRESHOLD) + { + + if (partitionSize == 2) + { + SwapIfGreater(keys, comparer!, 0, 1); + return; + } + + if (partitionSize == 3) + { + SwapIfGreater(keys, comparer!, 0, 1); + SwapIfGreater(keys, comparer!, 0, 2); + SwapIfGreater(keys, comparer!, 1, 2); + return; + } + + InsertionSort(keys[..partitionSize], comparer!); + return; + } + + if (depthLimit == 0) + { + HeapSort(keys[..partitionSize], comparer!); + return; + } + depthLimit--; + + var p = PickPivotAndPartition(keys[..partitionSize], comparer!); + + // Note we've already partitioned around the pivot and do not have to move the pivot again. + IntroSort(keys[(p + 1)..partitionSize], depthLimit, comparer!); + partitionSize = p; + } + } + + private static int PickPivotAndPartition(Span keys, Comparison comparer) + { + Debug.Assert(keys.Length >= SortUtils.INTROSORT_SIZE_THRESHOLD); + Debug.Assert(comparer != null); + + var hi = keys.Length - 1; + + // Compute median-of-three. But also partition them, since we've done the comparison. + var middle = hi >> 1; + + // Sort lo, mid and hi appropriately, then pick mid as the pivot. + SwapIfGreater(keys, comparer!, 0, middle); // swap the low with the mid point + SwapIfGreater(keys, comparer!, 0, hi); // swap the low with the high + SwapIfGreater(keys, comparer!, middle, hi); // swap the middle with the high + + var pivot = keys[middle]; + Swap(keys, middle, hi - 1); + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + + while (left < right) + { + while (comparer!(keys[++left], pivot) < 0) + ; + while (comparer(pivot, keys[--right]) < 0) + ; + + if (left >= right) + break; + + Swap(keys, left, right); + } + + // Put pivot in the right location. + if (left != hi - 1) + { + Swap(keys, left, hi - 1); + } + return left; + } + + private static void HeapSort(Span keys, Comparison comparer) + { + Debug.Assert(comparer != null); + Debug.Assert(!keys.IsEmpty); + + var n = keys.Length; + for (var i = n >> 1; i >= 1; i--) + { + DownHeap(keys, i, n, comparer!); + } + + for (var i = n; i > 1; i--) + { + Swap(keys, 0, i - 1); + DownHeap(keys, 1, i - 1, comparer!); + } + } + + private static void DownHeap(Span keys, int i, int n, Comparison comparer) + { + Debug.Assert(comparer != null); + + var d = keys[i - 1]; + while (i <= n >> 1) + { + var child = 2 * i; + if (child < n && comparer!(keys[child - 1], keys[child]) < 0) + { + child++; + } + + if (!(comparer!(d, keys[child - 1]) < 0)) + break; + + keys[i - 1] = keys[child - 1]; + i = child; + } + + keys[i - 1] = d; + } + + private static void InsertionSort(Span keys, Comparison comparer) + { + for (var i = 0; i < keys.Length - 1; i++) + { + var t = keys[i + 1]; + + var j = i; + while (j >= 0 && comparer(t, keys[j]) < 0) + { + keys[j + 1] = keys[j]; + j--; + } + + keys[j + 1] = t; + } + } +} + +internal sealed class GenericArraySortHelper : IArraySortHelper + where T : IComparable +{ + // Do not add a constructor to this class because ArraySortHelper.CreateSortHelper will not execute it + + #region IArraySortHelper Members + + public void Sort(Span keys, IComparer? comparer) + { + try + { + if (comparer == null || comparer == Comparer.Default) + { + if (keys.Length > 1) + { + // For floating-point, do a pre-pass to move all NaNs to the beginning + // so that we can do an optimized comparison as part of the actual sort + // on the remainder of the values. + if (typeof(T) == typeof(double) || + typeof(T) == typeof(float)) + { + var nanLeft = SortUtils.MoveNansToFront(keys, default(Span)); + if (nanLeft == keys.Length) + { + return; + } + keys = keys[nanLeft..]; + } + + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); + } + } + else + { + ArraySortHelper.IntrospectiveSort(keys, comparer.Compare); + } + } + catch (IndexOutOfRangeException) + { + SortUtils.ThrowArgumentException_BadComparer(comparer); + } + catch (Exception e) + { + ThrowHelper.ThrowInvalidOperationException(SortUtils.InvalidOperation_IComparerFailed, e); + } + } + + #endregion + + /// Swaps the values in the two references if the first is greater than the second. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SwapIfGreater(ref T i, ref T j) + { + if (i != null && GreaterThan(ref i, ref j)) + { + Swap(ref i, ref j); + } + } + + /// Swaps the values in the two references, regardless of whether the two references are the same. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(ref T i, ref T j) + { + Debug.Assert(!Unsafe.AreSame(ref i, ref j)); + + (j, i) = (i, j); + } + + private static void IntroSort(Span keys, int depthLimit) + { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); + + var partitionSize = keys.Length; + while (partitionSize > 1) + { + if (partitionSize <= SortUtils.INTROSORT_SIZE_THRESHOLD) + { + if (partitionSize == 2) + { + SwapIfGreater(ref keys[0], ref keys[1]); + return; + } + + if (partitionSize == 3) + { + ref var hiRef = ref keys[2]; + ref var him1Ref = ref keys[1]; + ref var loRef = ref keys[0]; + + SwapIfGreater(ref loRef, ref him1Ref); + SwapIfGreater(ref loRef, ref hiRef); + SwapIfGreater(ref him1Ref, ref hiRef); + return; + } + + InsertionSort(keys[..partitionSize]); + return; + } + + if (depthLimit == 0) + { + HeapSort(keys[..partitionSize]); + return; + } + depthLimit--; + + var p = PickPivotAndPartition(keys[..partitionSize]); + + // Note we've already partitioned around the pivot and do not have to move the pivot again. + IntroSort(keys[(p + 1)..partitionSize], depthLimit); + partitionSize = p; + } + } + + private static int PickPivotAndPartition(Span keys) + { + Debug.Assert(keys.Length >= SortUtils.INTROSORT_SIZE_THRESHOLD); + + // Use median-of-three to select a pivot. Grab a reference to the 0th, Length-1th, and Length/2th elements, and sort them. + ref var zeroRef = ref MemoryMarshal.GetReference(keys); + ref var lastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 1); + ref var middleRef = ref Unsafe.Add(ref zeroRef, (keys.Length - 1) >> 1); + SwapIfGreater(ref zeroRef, ref middleRef); + SwapIfGreater(ref zeroRef, ref lastRef); + SwapIfGreater(ref middleRef, ref lastRef); + + // Select the middle value as the pivot, and move it to be just before the last element. + ref var nextToLastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 2); + var pivot = middleRef; + Swap(ref middleRef, ref nextToLastRef); + + // Walk the left and right pointers, swapping elements as necessary, until they cross. + ref T leftRef = ref zeroRef!, rightRef = ref nextToLastRef!; + while (Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) + { + if (pivot == null) + { + while (Unsafe.IsAddressLessThan(ref leftRef!, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) + ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) != null) + ; + } + else + { + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && GreaterThan(ref pivot, ref leftRef = ref Unsafe.Add(ref leftRef, 1))) + ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && LessThan(ref pivot, ref rightRef = ref Unsafe.Add(ref rightRef, -1))) + ; + } + + if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef!)) + { + break; + } + + Swap(ref leftRef, ref rightRef); + } + + // Put the pivot in the correct location. + if (!Unsafe.AreSame(ref leftRef, ref nextToLastRef)) + { + Swap(ref leftRef, ref nextToLastRef); + } + return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf()); + } + + private static void HeapSort(Span keys) + { + Debug.Assert(!keys.IsEmpty); + + var n = keys.Length; + for (var i = n >> 1; i >= 1; i--) + { + DownHeap(keys, i, n); + } + + for (var i = n; i > 1; i--) + { + Swap(ref keys[0], ref keys[i - 1]); + DownHeap(keys, 1, i - 1); + } + } + + private static void DownHeap(Span keys, int i, int n) + { + var d = keys[i - 1]; + while (i <= n >> 1) + { + var child = 2 * i; + if (child < n && (keys[child - 1] == null || LessThan(ref keys[child - 1], ref keys[child]))) + { + child++; + } + + if (keys[child - 1] == null || !LessThan(ref d, ref keys[child - 1])) + break; + + keys[i - 1] = keys[child - 1]; + i = child; + } + + keys[i - 1] = d; + } + + private static void InsertionSort(Span keys) + { + for (var i = 0; i < keys.Length - 1; i++) + { + var t = Unsafe.Add(ref MemoryMarshal.GetReference(keys), i + 1); + + var j = i; + while (j >= 0 && (t == null || LessThan(ref t, ref Unsafe.Add(ref MemoryMarshal.GetReference(keys), j)))) + { + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j); + j--; + } + + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = t!; + } + } + + // - These methods exist for use in sorting, where the additional operations present in + // the CompareTo methods that would otherwise be used on these primitives add non-trivial overhead, + // in particular for floating point where the CompareTo methods need to factor in NaNs. + // - The floating-point comparisons here assume no NaNs, which is valid only because the sorting routines + // themselves special-case NaN with a pre-pass that ensures none are present in the values being sorted + // by moving them all to the front first and then sorting the rest. + // - These are duplicated here rather than being on a helper type due to current limitations around generic inlining. + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call + private static bool LessThan(ref T left, ref T right) + => typeof(T) == typeof(byte) + ? (byte)(object)left < (byte)(object)right + : typeof(T) == typeof(sbyte) + ? (sbyte)(object)left < (sbyte)(object)right + : typeof(T) == typeof(ushort) + ? (ushort)(object)left < (ushort)(object)right + : typeof(T) == typeof(short) + ? (short)(object)left < (short)(object)right + : typeof(T) == typeof(uint) + ? (uint)(object)left < (uint)(object)right + : typeof(T) == typeof(int) + ? (int)(object)left < (int)(object)right + : typeof(T) == typeof(ulong) + ? (ulong)(object)left < (ulong)(object)right + : typeof(T) == typeof(long) + ? (long)(object)left < (long)(object)right + : typeof(T) == typeof(nuint) + ? (nuint)(object)left < (nuint)(object)right + : typeof(T) == typeof(nint) + ? (nint)(object)left < (nint)(object)right + : typeof(T) == typeof(float) + ? (float)(object)left < (float)(object)right + : typeof(T) == typeof(double) + ? (double)(object)left < (double)(object)right + : left.CompareTo(right) < 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call + private static bool GreaterThan(ref T left, ref T right) + => typeof(T) == typeof(byte) + ? (byte)(object)left > (byte)(object)right + : typeof(T) == typeof(sbyte) + ? (sbyte)(object)left > (sbyte)(object)right + : typeof(T) == typeof(ushort) + ? (ushort)(object)left > (ushort)(object)right + : typeof(T) == typeof(short) + ? (short)(object)left > (short)(object)right + : typeof(T) == typeof(uint) + ? (uint)(object)left > (uint)(object)right + : typeof(T) == typeof(int) + ? (int)(object)left > (int)(object)right + : typeof(T) == typeof(ulong) + ? (ulong)(object)left > (ulong)(object)right + : typeof(T) == typeof(long) + ? (long)(object)left > (long)(object)right + : typeof(T) == typeof(nuint) + ? (nuint)(object)left > (nuint)(object)right + : typeof(T) == typeof(nint) + ? (nint)(object)left > (nint)(object)right + : typeof(T) == typeof(float) + ? (float)(object)left > (float)(object)right + : typeof(T) == typeof(double) + ? (double)(object)left > (double)(object)right + : left.CompareTo(right) > 0; +} + +#endregion + +#region ArraySortHelper for paired key and value arrays + +internal sealed class ArraySortHelper : IArraySortHelper +{ + public static IArraySortHelper Default { get; } = CreateArraySortHelper(); + + private static IArraySortHelper CreateArraySortHelper() + => typeof(IComparable).IsAssignableFrom(typeof(TKey)) + ? (IArraySortHelper)Activator.CreateInstance(typeof(GenericArraySortHelper<,>).MakeGenericType(typeof(TKey), typeof(TValue))) + : new ArraySortHelper(); + + public void Sort(Span keys, Span values, IComparer? comparer) + { + // Add a try block here to detect IComparers (or their + // underlying IComparables, etc) that are bogus. + try + { + IntrospectiveSort(keys, values, comparer ?? Comparer.Default); + } + catch (IndexOutOfRangeException) + { + SortUtils.ThrowArgumentException_BadComparer(comparer); + } + catch (Exception e) + { + ThrowHelper.ThrowInvalidOperationException(SortUtils.InvalidOperation_IComparerFailed, e); + } + } + + private static void SwapIfGreaterWithValues(Span keys, Span values, IComparer comparer, int i, int j) + { + Debug.Assert(comparer != null); + Debug.Assert(0 <= i && i < keys.Length && i < values.Length); + Debug.Assert(0 <= j && j < keys.Length && j < values.Length); + Debug.Assert(i != j); + + if (comparer!.Compare(keys[i], keys[j]) > 0) + { + (keys[j], keys[i]) = (keys[i], keys[j]); + + (values[j], values[i]) = (values[i], values[j]); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(Span keys, Span values, int i, int j) + { + Debug.Assert(i != j); + + (keys[j], keys[i]) = (keys[i], keys[j]); + + (values[j], values[i]) = (values[i], values[j]); + } + + public static void IntrospectiveSort(Span keys, Span values, IComparer comparer) + { + Debug.Assert(comparer != null); + Debug.Assert(keys.Length == values.Length); + + if (keys.Length > 1) + { + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer!); + } + } + + public static void IntroSort(Span keys, Span values, int depthLimit, IComparer comparer) + { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); + Debug.Assert(comparer != null); + + var partitionSize = keys.Length; + while (partitionSize > 1) + { + if (partitionSize <= SortUtils.INTROSORT_SIZE_THRESHOLD) + { + + if (partitionSize == 2) + { + SwapIfGreaterWithValues(keys, values, comparer!, 0, 1); + return; + } + + if (partitionSize == 3) + { + SwapIfGreaterWithValues(keys, values, comparer!, 0, 1); + SwapIfGreaterWithValues(keys, values, comparer!, 0, 2); + SwapIfGreaterWithValues(keys, values, comparer!, 1, 2); + return; + } + + InsertionSort(keys[..partitionSize], values[..partitionSize], comparer!); + return; + } + + if (depthLimit == 0) + { + HeapSort(keys[..partitionSize], values[..partitionSize], comparer!); + return; + } + depthLimit--; + + var p = PickPivotAndPartition(keys[..partitionSize], values[..partitionSize], comparer!); + + // Note we've already partitioned around the pivot and do not have to move the pivot again. + IntroSort(keys[(p + 1)..partitionSize], values[(p + 1)..partitionSize], depthLimit, comparer!); + partitionSize = p; + } + } + + private static int PickPivotAndPartition(Span keys, Span values, IComparer comparer) + { + Debug.Assert(keys.Length >= SortUtils.INTROSORT_SIZE_THRESHOLD); + Debug.Assert(comparer != null); + + var hi = keys.Length - 1; + + // Compute median-of-three. But also partition them, since we've done the comparison. + var middle = hi >> 1; + + // Sort lo, mid and hi appropriately, then pick mid as the pivot. + SwapIfGreaterWithValues(keys, values, comparer!, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, comparer!, 0, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, comparer!, middle, hi); // swap the middle with the high + + var pivot = keys[middle]; + Swap(keys, values, middle, hi - 1); + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + + while (left < right) + { + while (comparer!.Compare(keys[++left], pivot) < 0) + ; + while (comparer.Compare(pivot, keys[--right]) < 0) + ; + + if (left >= right) + break; + + Swap(keys, values, left, right); + } + + // Put pivot in the right location. + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } + return left; + } + + private static void HeapSort(Span keys, Span values, IComparer comparer) + { + Debug.Assert(comparer != null); + Debug.Assert(!keys.IsEmpty); + + var n = keys.Length; + for (var i = n >> 1; i >= 1; i--) + { + DownHeap(keys, values, i, n, comparer!); + } + + for (var i = n; i > 1; i--) + { + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1, comparer!); + } + } + + private static void DownHeap(Span keys, Span values, int i, int n, IComparer comparer) + { + Debug.Assert(comparer != null); + + var d = keys[i - 1]; + var dValue = values[i - 1]; + + while (i <= n >> 1) + { + var child = 2 * i; + if (child < n && comparer!.Compare(keys[child - 1], keys[child]) < 0) + { + child++; + } + + if (!(comparer!.Compare(d, keys[child - 1]) < 0)) + break; + + keys[i - 1] = keys[child - 1]; + values[i - 1] = values[child - 1]; + i = child; + } + + keys[i - 1] = d; + values[i - 1] = dValue; + } + + private static void InsertionSort(Span keys, Span values, IComparer comparer) + { + Debug.Assert(comparer != null); + + for (var i = 0; i < keys.Length - 1; i++) + { + var t = keys[i + 1]; + var tValue = values[i + 1]; + + var j = i; + while (j >= 0 && comparer!.Compare(t, keys[j]) < 0) + { + keys[j + 1] = keys[j]; + values[j + 1] = values[j]; + j--; + } + + keys[j + 1] = t; + values[j + 1] = tValue; + } + } +} + +internal sealed class GenericArraySortHelper : IArraySortHelper + where TKey : IComparable +{ + public void Sort(Span keys, Span values, IComparer? comparer) + { + // Add a try block here to detect IComparers (or their + // underlying IComparables, etc) that are bogus. + try + { + if (comparer == null || comparer == Comparer.Default) + { + if (keys.Length > 1) + { + // For floating-point, do a pre-pass to move all NaNs to the beginning + // so that we can do an optimized comparison as part of the actual sort + // on the remainder of the values. + if (typeof(TKey) == typeof(double) || + typeof(TKey) == typeof(float)) + { + var nanLeft = SortUtils.MoveNansToFront(keys, values); + if (nanLeft == keys.Length) + { + return; + } + keys = keys[nanLeft..]; + values = values[nanLeft..]; + } + + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); + } + } + else + { + ArraySortHelper.IntrospectiveSort(keys, values, comparer); + } + } + catch (IndexOutOfRangeException) + { + SortUtils.ThrowArgumentException_BadComparer(comparer); + } + catch (Exception e) + { + ThrowHelper.ThrowInvalidOperationException(SortUtils.InvalidOperation_IComparerFailed, e); + } + } + + private static void SwapIfGreaterWithValues(Span keys, Span values, int i, int j) + { + Debug.Assert(i != j); + + ref var keyRef = ref keys[i]; + if (keyRef != null && GreaterThan(ref keyRef, ref keys[j])) + { + var key = keyRef; + keys[i] = keys[j]; + keys[j] = key; + + (values[j], values[i]) = (values[i], values[j]); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(Span keys, Span values, int i, int j) + { + Debug.Assert(i != j); + + (keys[j], keys[i]) = (keys[i], keys[j]); + + (values[j], values[i]) = (values[i], values[j]); + } + + private static void IntroSort(Span keys, Span values, int depthLimit) + { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); + + var partitionSize = keys.Length; + while (partitionSize > 1) + { + if (partitionSize <= SortUtils.INTROSORT_SIZE_THRESHOLD) + { + + if (partitionSize == 2) + { + SwapIfGreaterWithValues(keys, values, 0, 1); + return; + } + + if (partitionSize == 3) + { + SwapIfGreaterWithValues(keys, values, 0, 1); + SwapIfGreaterWithValues(keys, values, 0, 2); + SwapIfGreaterWithValues(keys, values, 1, 2); + return; + } + + InsertionSort(keys[..partitionSize], values[..partitionSize]); + return; + } + + if (depthLimit == 0) + { + HeapSort(keys[..partitionSize], values[..partitionSize]); + return; + } + depthLimit--; + + var p = PickPivotAndPartition(keys[..partitionSize], values[..partitionSize]); + + // Note we've already partitioned around the pivot and do not have to move the pivot again. + IntroSort(keys[(p + 1)..partitionSize], values[(p + 1)..partitionSize], depthLimit); + partitionSize = p; + } + } + + private static int PickPivotAndPartition(Span keys, Span values) + { + Debug.Assert(keys.Length >= SortUtils.INTROSORT_SIZE_THRESHOLD); + + var hi = keys.Length - 1; + + // Compute median-of-three. But also partition them, since we've done the comparison. + var middle = hi >> 1; + + // Sort lo, mid and hi appropriately, then pick mid as the pivot. + SwapIfGreaterWithValues(keys, values, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, 0, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, middle, hi); // swap the middle with the high + + var pivot = keys[middle]; + Swap(keys, values, middle, hi - 1); + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + + while (left < right) + { + if (pivot == null) + { + while (left < (hi - 1) && keys[++left] == null) + ; + while (right > 0 && keys[--right] != null) + ; + } + else + { + while (GreaterThan(ref pivot, ref keys[++left])) + ; + while (LessThan(ref pivot, ref keys[--right])) + ; + } + + if (left >= right) + break; + + Swap(keys, values, left, right); + } + + // Put pivot in the right location. + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } + return left; + } + + private static void HeapSort(Span keys, Span values) + { + Debug.Assert(!keys.IsEmpty); + + var n = keys.Length; + for (var i = n >> 1; i >= 1; i--) + { + DownHeap(keys, values, i, n); + } + + for (var i = n; i > 1; i--) + { + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1); + } + } + + private static void DownHeap(Span keys, Span values, int i, int n) + { + var d = keys[i - 1]; + var dValue = values[i - 1]; + + while (i <= n >> 1) + { + var child = 2 * i; + if (child < n && (keys[child - 1] == null || LessThan(ref keys[child - 1], ref keys[child]))) + { + child++; + } + + if (keys[child - 1] == null || !LessThan(ref d, ref keys[child - 1])) + break; + + keys[i - 1] = keys[child - 1]; + values[i - 1] = values[child - 1]; + i = child; + } + + keys[i - 1] = d; + values[i - 1] = dValue; + } + + private static void InsertionSort(Span keys, Span values) + { + for (var i = 0; i < keys.Length - 1; i++) + { + var t = keys[i + 1]; + var tValue = values[i + 1]; + + var j = i; + while (j >= 0 && (t == null || LessThan(ref t, ref keys[j]))) + { + keys[j + 1] = keys[j]; + values[j + 1] = values[j]; + j--; + } + + keys[j + 1] = t!; + values[j + 1] = tValue; + } + } + + // - These methods exist for use in sorting, where the additional operations present in + // the CompareTo methods that would otherwise be used on these primitives add non-trivial overhead, + // in particular for floating point where the CompareTo methods need to factor in NaNs. + // - The floating-point comparisons here assume no NaNs, which is valid only because the sorting routines + // themselves special-case NaN with a pre-pass that ensures none are present in the values being sorted + // by moving them all to the front first and then sorting the rest. + // - These are duplicated here rather than being on a helper type due to current limitations around generic inlining. + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call + private static bool LessThan(ref TKey left, ref TKey right) + => typeof(TKey) == typeof(byte) + ? (byte)(object)left < (byte)(object)right + : typeof(TKey) == typeof(sbyte) + ? (sbyte)(object)left < (sbyte)(object)right + : typeof(TKey) == typeof(ushort) + ? (ushort)(object)left < (ushort)(object)right + : typeof(TKey) == typeof(short) + ? (short)(object)left < (short)(object)right + : typeof(TKey) == typeof(uint) + ? (uint)(object)left < (uint)(object)right + : typeof(TKey) == typeof(int) + ? (int)(object)left < (int)(object)right + : typeof(TKey) == typeof(ulong) + ? (ulong)(object)left < (ulong)(object)right + : typeof(TKey) == typeof(long) + ? (long)(object)left < (long)(object)right + : typeof(TKey) == typeof(nuint) + ? (nuint)(object)left < (nuint)(object)right + : typeof(TKey) == typeof(nint) + ? (nint)(object)left < (nint)(object)right + : typeof(TKey) == typeof(float) + ? (float)(object)left < (float)(object)right + : typeof(TKey) == typeof(double) + ? (double)(object)left < (double)(object)right + : left.CompareTo(right) < 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] // compiles to a single comparison or method call + private static bool GreaterThan(ref TKey left, ref TKey right) + => typeof(TKey) == typeof(byte) + ? (byte)(object)left > (byte)(object)right + : typeof(TKey) == typeof(sbyte) + ? (sbyte)(object)left > (sbyte)(object)right + : typeof(TKey) == typeof(ushort) + ? (ushort)(object)left > (ushort)(object)right + : typeof(TKey) == typeof(short) + ? (short)(object)left > (short)(object)right + : typeof(TKey) == typeof(uint) + ? (uint)(object)left > (uint)(object)right + : typeof(TKey) == typeof(int) + ? (int)(object)left > (int)(object)right + : typeof(TKey) == typeof(ulong) + ? (ulong)(object)left > (ulong)(object)right + : typeof(TKey) == typeof(long) + ? (long)(object)left > (long)(object)right + : typeof(TKey) == typeof(nuint) + ? (nuint)(object)left > (nuint)(object)right + : typeof(TKey) == typeof(nint) + ? (nint)(object)left > (nint)(object)right + : typeof(TKey) == typeof(float) + ? (float)(object)left > (float)(object)right + : typeof(TKey) == typeof(double) + ? (double)(object)left > (double)(object)right + : left.CompareTo(right) > 0; +} + +#endregion + +/// Helper methods for use in array/span sorting routines. +internal static class SortUtils +{ + public static int MoveNansToFront(Span keys, Span values) where TKey : notnull + { + Debug.Assert(typeof(TKey) == typeof(double) || typeof(TKey) == typeof(float)); + + var left = 0; + + for (var i = 0; i < keys.Length; i++) + { + if ((typeof(TKey) == typeof(double) && double.IsNaN((double)(object)keys[i])) || + (typeof(TKey) == typeof(float) && float.IsNaN((float)(object)keys[i]))) + { + (keys[i], keys[left]) = (keys[left], keys[i]); + + if ((uint)i < (uint)values.Length) // check to see if we have values + { + (values[i], values[left]) = (values[left], values[i]); + } + + left++; + } + } + + return left; + } + + // This is the threshold where Introspective sort switches to Insertion sort. + // Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. + // Large value types may benefit from a smaller number. + internal const int INTROSORT_SIZE_THRESHOLD = 16; + + [DoesNotReturn] + internal static void ThrowArgumentException_BadComparer(object? comparer) + => throw new ArgumentException(string.Format(Arg_BogusIComparer, comparer)); + + internal static string InvalidOperation_IComparerFailed => "Failed to compare two elements in the array."; + internal static string Arg_BogusIComparer + => "Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: '{0}'."; +} + +internal interface IArraySortHelper +{ + void Sort(Span keys, Span values, IComparer? comparer); +} + +internal interface IArraySortHelper +{ + void Sort(Span keys, IComparer? comparer); +} + +internal static class BitOperations +{ + private static ReadOnlySpan Log2DeBruijn + => new byte[32] + { + 00, 09, 01, 10, 13, 21, 02, 29, + 11, 14, 16, 18, 22, 25, 03, 30, + 08, 12, 20, 28, 15, 17, 24, 07, + 19, 27, 23, 06, 26, 05, 04, 31 + }; + + /// + /// Returns the integer (floor) log of the specified value, base 2. + /// Note that by convention, input value 0 returns 0 since log(0) is undefined. + /// + /// The value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + //[CLSCompliant(false)] + public static int Log2(uint value) + { + // The 0->0 contract is fulfilled by setting the LSB to 1. + // Log(1) is 0, and setting the LSB for values > 1 does not change the log2 result. + value |= 1; + +#if probablyNotSupportedOnUnity + // value lzcnt actual expected + // ..0001 31 31-31 0 + // ..0010 30 31-30 1 + // 0010.. 2 31-2 29 + // 0100.. 1 31-1 30 + // 1000.. 0 31-0 31 + if (Lzcnt.IsSupported) + { + return 31 ^ (int)Lzcnt.LeadingZeroCount(value); + } + + if (ArmBase.IsSupported) + { + return 31 ^ ArmBase.LeadingZeroCount(value); + } + + // BSR returns the log2 result directly. However BSR is slower than LZCNT + // on AMD processors, so we leave it as a fallback only. + if (X86Base.IsSupported) + { + return (int)X86Base.BitScanReverse(value); + } +#endif + + // Fallback contract is 0->0 + return Log2SoftwareFallback(value); + } + + /// + /// Returns the integer (floor) log of the specified value, base 2. + /// Note that by convention, input value 0 returns 0 since Log(0) is undefined. + /// Does not directly use any hardware intrinsics, nor does it incur branching. + /// + /// The value. + private static int Log2SoftwareFallback(uint value) + { + // No AggressiveInlining due to large method size + // Has conventional contract 0->0 (Log(0) is undefined) + + // Fill trailing zeros with ones, eg 00010010 becomes 00011111 + value |= value >> 01; + value |= value >> 02; + value |= value >> 04; + value |= value >> 08; + value |= value >> 16; + + // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check + return Unsafe.AddByteOffset( + // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_1100_0100_1010_1100_1101_1101u + ref MemoryMarshal.GetReference(Log2DeBruijn), + // uint|long -> IntPtr cast on 32-bit platforms does expensive overflow checks not needed here + (IntPtr)(int)((value * 0x07C4ACDDu) >> 27)); + } +} \ No newline at end of file diff --git a/Source/FisheryLib/BoolExtensions.cs b/Source/FisheryLib/BoolExtensions.cs new file mode 100644 index 0000000..5942908 --- /dev/null +++ b/Source/FisheryLib/BoolExtensions.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/BoolExtensions.cs + +using System.Runtime.CompilerServices; + +namespace FisheryLib; + +/// +/// Helpers for working with the type. +/// +public static class BoolExtensions +{ + /// + /// Converts the given value into a . + /// + /// The input value to convert. + /// 1 if is , 0 otherwise. + /// This method does not contain branching instructions. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe byte ToByte(this bool flag) + { + // Whenever we need to take the address of an argument, we make a local copy first. + // This will be removed by the JIT anyway, but it can help produce better codegen and + // remove unwanted stack spills if the caller is using constant arguments. This is + // because taking the address of an argument can interfere with some of the flow + // analysis executed by the JIT, which can in some cases block constant propagation. + bool copy = flag; + + return *(byte*)© + } + + /// + /// Converts the given value to an mask with + /// all bits representing the value of the input flag (either 0xFFFFFFFF or 0x00000000). + /// + /// The input value to convert. + /// 0xFFFFFFFF if is , 0x00000000 otherwise. + /// + /// This method does not contain branching instructions, and it is only guaranteed to work with + /// values being either 0 or 1. Operations producing a result, + /// such as numerical comparisons, always result in a valid value. If the value is + /// produced by fields with a custom , + /// or by using or other unsafe APIs to directly manipulate the underlying + /// data though, it is responsibility of the caller to ensure the validity of the provided value. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int ToBitwiseMask32(this bool flag) + { + bool copy = flag; + byte rangeFlag = *(byte*)© + int negativeFlag = rangeFlag - 1; + int mask = ~negativeFlag; + + return mask; + } + + /// + /// Converts the given value to a mask with + /// all bits representing the value of the input flag (either all 1s or 0s). + /// + /// The input value to convert. + /// All 1s if is , all 0s otherwise. + /// This method does not contain branching instructions. See additional note in . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe long ToBitwiseMask64(this bool flag) + { + bool copy = flag; + byte rangeFlag = *(byte*)© + long negativeFlag = (long)rangeFlag - 1; + long mask = ~negativeFlag; + + return mask; + } +} \ No newline at end of file diff --git a/Source/FisheryLib/CollectionExtensions.cs b/Source/FisheryLib/CollectionExtensions.cs new file mode 100644 index 0000000..136f7de --- /dev/null +++ b/Source/FisheryLib/CollectionExtensions.cs @@ -0,0 +1,333 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace FisheryLib; +public static class CollectionExtensions +{ + public static bool TryGetItem(this List list, int index, [NotNullWhen(true)] out T? item) + { + if (list.Count > index) + { + item = list[index]!; + return true; + } + + item = default; + return false; + } + + /// + /// Taken from Span<>.this[] and slower than List<>.this[] due to the ArrayAdjustment + /// + internal static T GetItemUnchecked(this List list, int index) + => Unsafe.Add(ref Unsafe.AddByteOffset(ref Unsafe.As>(list._items).Data, PerTypeValues.ArrayAdjustment), index)!; + + [StructLayout(LayoutKind.Sequential)] + private sealed class Pinnable + { + public T? Data; + } + private static class PerTypeValues + { + public static readonly IntPtr ArrayAdjustment = MeasureArrayAdjustment(); + private static IntPtr MeasureArrayAdjustment() + { + var array = new T[1]; + return Unsafe.ByteOffset(ref Unsafe.As>(array).Data!, ref array[0]); + } + } + + public static bool TryGetItem(this T[] array, int index, out T? item) + { + if (array.Length > index) + { + item = array[index]; + return true; + } + + item = default; + return false; + } + + public static T[] ToArray(this IEnumerable enumerable, int length) + { + var array = new T[length]; + + if (enumerable is IList ilist) + array.Fill(ilist); + else + array.FillUsingEnumerable(enumerable); + + return array; + } + + public static Telement[] ToArray(this Tenumerable enumerable, Telement[] destination) + where Tenumerable : IList + { + Guard.IsNotNull(destination); + + destination.Fill(enumerable); + return destination; + } + + public static T[] ToArray(this IEnumerable enumerable, T[] destination) + { + Guard.IsNotNull(destination); + + if (enumerable is IList ilist) + destination.Fill(ilist); + else + destination.FillUsingEnumerable(enumerable); + + return destination; + } + + private static void FillUsingEnumerable(this T[] array, IEnumerable enumerable, int startIndex = 0, int count = -1) + { + var i = 0u; + foreach (var item in enumerable) + { + if (i >= (uint)count || startIndex >= array.Length) + break; + + array[startIndex++] = item; + i++; + } + } + + public static void Fill(this Telement[] array, Tcollection collection, int startIndex = 0, int count = -1) + where Tcollection : IList + { + Guard.IsNotNull(collection); + + if (count <= 0) + count = collection.Count; + + if (count <= array.Length - startIndex) + { + collection.CopyTo(array, startIndex); + return; + } + + for (var listIndex = 0; listIndex < count && startIndex < array.Length; startIndex++, listIndex++) + array[startIndex] = collection[listIndex]; + } + + public static void Fill(this T[] array, IEnumerable enumerable, int startIndex = 0, int count = -1) + { + Guard.IsNotNull(enumerable); + + if (enumerable is IList ilist) + array.Fill(ilist, startIndex, count); + else + array.FillUsingEnumerable(enumerable, startIndex, count); + } + + public static ref TValue GetReference(this Dictionary dictionary, TKey key) + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(key) & 0x7FFFFFFF; // HashCode.Get can handle null, & 0x7FFFFFFF removes any sign + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + return ref entry.value; + + bucket = entry.next; + } + } + return ref ThrowKeyNotFoundException(key); + } + + /// + /// Returns a reference to the value field of an entry if the key exists and an Unsafe.NullRef{TValue} if not. + /// Must be checked with Unsafe.IsNullRef before assigning to a regular var or field without ref. + /// + /// The key + /// ref TValue or Unsafe.NullRef{TValue} + public static ref TValue TryGetReferenceUnsafe(this Dictionary dictionary, TKey key) + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(key) & 0x7FFFFFFF; + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + return ref entry.value; + + bucket = entry.next; + } + } + return ref Unsafe.NullRef(); + } + + public static ref TValue TryGetReferenceUnsafe(this Dictionary dictionary, ref TKey key) + where TKey : struct + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(ref key)) + return ref entry.value; + + bucket = entry.next; + } + } + return ref Unsafe.NullRef(); + } + + public static TValue? TryGetValue(this Dictionary dictionary, ref TKey key) + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(ref key) & 0x7FFFFFFF; + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && Equality.EqualsByRef(ref entry.key, ref key)) + return entry.value; + + bucket = entry.next; + } + } + return default; + } + + [return: MaybeNull] + public static TValue TryGetValue(this Dictionary dictionary, TKey key) + { + if (dictionary.buckets != null) + { + var keyCode = HashCode.Get(key) & 0x7FFFFFFF; + + var bucket = dictionary.buckets[keyCode % dictionary.buckets.Length]; + while (bucket >= 0) + { + ref var entry = ref dictionary.entries[bucket]; + if (entry.hashCode == keyCode && entry.key.Equals(key)) + return entry.value; + + bucket = entry.next; + } + } + return default; + } + + [DoesNotReturn] + private static ref V ThrowKeyNotFoundException(T key) + { + Guard.IsNotNull(key); + ThrowKeyNotFoundException(key); + return ref Unsafe.NullRef(); + } + + [DoesNotReturn] + private static void ThrowKeyNotFoundException(object key) + => throw new KeyNotFoundException( + string.Format("The given key '{0}' was not present in the dictionary.", key)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref int Version(this List list) => ref list._version; + + /// + /// Returns a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T[] ItemsUnchecked(this List list) => list._items; + + /// + /// Returns a span pointing to a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified. + /// + public static Span AsSpanUnchecked(this List list) => new(list._items, 0, list.Count); + + public static ReadOnlySpan AsReadOnlySpan(this List list) => new(list._items, 0, list.Count); + + public static void ReplaceContentsWith(this List list, V collection) where V : ICollection + { + if (ReferenceEquals(list, collection)) + return; + + if (collection is null + || (collection.Count is var collectionCount + && collectionCount == 0)) + { + list.Clear(); + return; + } + + if (collectionCount <= list.Count) + { + if (collectionCount < list.Count) + list.RemoveRange(collectionCount, list.Count - collectionCount); + collection.CopyTo(list._items, 0); + } + else + { + list._items = new T[collectionCount]; + collection.CopyTo(list._items, 0); + list._size = collectionCount; + } + list._version++; + } + + public static IList TryNew(IEnumerable enumerable, Type type) => GetListExtensionMethods(type).New(enumerable); + + public static void TryAddRange(this IList list, T collection, Type type) where T : ICollection => GetListExtensionMethods(type).AddRange(list, collection); + + public static Array TryToArray(this IList list, Type type) => GetListExtensionMethods(type).ToArray(list); + + public static GenericBase GetListExtensionMethods(Type type) + => ListExtensionCache.TryGetValue(type) + ?? CreateListExtensionMethods(type); + + private static GenericBase CreateListExtensionMethods(Type type) + { + var methods = (GenericBase)Activator.CreateInstance(typeof(Generic<>).MakeGenericType(type)); + ListExtensionCache[type] = methods; + return methods; + } + + private static Dictionary ListExtensionCache => _listExtensionCache ??= new(); + + [ThreadStatic] + private static Dictionary? _listExtensionCache; + + public abstract class GenericBase + { + public abstract void AddRange(IList list, ICollection collection); + public abstract Array ToArray(IList list); + public abstract IList New(IEnumerable enumerable); + } + + public class Generic : GenericBase + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void AddRange(IList list, ICollection collection) => ((List)list).AddRange((IEnumerable)collection); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override Array ToArray(IList list) => ((List)list).ToArray(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override IList New(IEnumerable enumerable) => new List((IEnumerable)enumerable); + } +} \ No newline at end of file diff --git a/Source/FisheryLib/Convert.cs b/Source/FisheryLib/Convert.cs new file mode 100644 index 0000000..40c8fe8 --- /dev/null +++ b/Source/FisheryLib/Convert.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Globalization; +using System.Runtime.CompilerServices; + +namespace FisheryLib; +public static class Convert +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe TTo To(TFrom from) where TFrom : IConvertible + => FunctionPointers.Convert.To.Default(from, CultureInfo.InvariantCulture); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe TTo To(TFrom from, IFormatProvider provider) where TFrom : IConvertible + => FunctionPointers.Convert.To.Default(from, provider); +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Attributes/CallerArgumentExpressionAttribute.cs b/Source/FisheryLib/Diagnostics/Attributes/CallerArgumentExpressionAttribute.cs new file mode 100644 index 0000000..ba668ba --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Attributes/CallerArgumentExpressionAttribute.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.CompilerServices; + +/// +/// An attribute that allows parameters to receive the expression of other parameters. +/// +/// Internal copy from the BCL attribute. +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] +internal sealed class CallerArgumentExpressionAttribute : Attribute +{ + /// + /// Initializes a new instance of the class. + /// + /// The condition parameter value. + public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName; + + /// + /// Gets the parameter name the expression is retrieved from. + /// + public string ParameterName { get; } +} \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs b/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs new file mode 100644 index 0000000..aacaa23 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Extensions/TypeExtensions.cs @@ -0,0 +1,162 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +/// Helpers for working with types. +/// +public static class TypeExtensions +{ + /// + /// The mapping of built-in types to their simple representation. + /// + private static readonly IReadOnlyDictionary BuiltInTypesMap = new Dictionary + { + [typeof(bool)] = "bool", + [typeof(byte)] = "byte", + [typeof(sbyte)] = "sbyte", + [typeof(short)] = "short", + [typeof(ushort)] = "ushort", + [typeof(char)] = "char", + [typeof(int)] = "int", + [typeof(uint)] = "uint", + [typeof(float)] = "float", + [typeof(long)] = "long", + [typeof(ulong)] = "ulong", + [typeof(double)] = "double", + [typeof(decimal)] = "decimal", + [typeof(object)] = "object", + [typeof(string)] = "string", + [typeof(void)] = "void" + }; + + /// + /// A thread-safe mapping of precomputed string representation of types. + /// + private static readonly ConditionalWeakTable DisplayNames = new(); + + /// + /// Returns a simple string representation of a type. + /// + /// The input type. + /// The string representation of . + public static string ToTypeString(this Type type) + { + // Local function to create the formatted string for a given type + static string FormatDisplayString(Type type, int genericTypeOffset, ReadOnlySpan typeArguments) + { + // Primitive types use the keyword name + if (BuiltInTypesMap.TryGetValue(type, out var typeName)) + { + return typeName!; + } + + // Array types are displayed as Foo[] + if (type.IsArray) + { + var elementType = type.GetElementType()!; + var rank = type.GetArrayRank(); + + return $"{FormatDisplayString(elementType, 0, elementType.GetGenericArguments())}[{new string(',', rank - 1)}]"; + } + + // By checking generic types here we are only interested in specific cases, + // ie. nullable value types or value tuples. We have a separate path for custom + // generic types, as we can't rely on this API in that case, as it doesn't show + // a difference between nested types that are themselves generic, or nested simple + // types from a generic declaring type. To deal with that, we need to manually track + // the offset within the array of generic arguments for the whole constructed type. + if (type.IsGenericType) + { + var genericTypeDefinition = type.GetGenericTypeDefinition(); + + // Nullable types are displayed as T? + if (genericTypeDefinition == typeof(Nullable<>)) + { + var nullableArguments = type.GetGenericArguments(); + + return $"{FormatDisplayString(nullableArguments[0], 0, nullableArguments)}?"; + } + + // ValueTuple types are displayed as (T1, T2) + if (genericTypeDefinition == typeof(ValueTuple<>) || + genericTypeDefinition == typeof(ValueTuple<,>) || + genericTypeDefinition == typeof(ValueTuple<,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,,>) || + genericTypeDefinition == typeof(ValueTuple<,,,,,,,>)) + { + var formattedTypes = type.GetGenericArguments().Select(t => FormatDisplayString(t, 0, t.GetGenericArguments())); + + return $"({string.Join(", ", formattedTypes)})"; + } + } + + string displayName; + + // Generic types + if (type.Name.Contains('`')) + { + // Retrieve the current generic arguments for the current type (leaf or not) + var tokens = type.Name.Split('`'); + var genericArgumentsCount = int.Parse(tokens[1]); + var typeArgumentsOffset = typeArguments.Length - genericTypeOffset - genericArgumentsCount; + var currentTypeArguments = typeArguments.Slice(typeArgumentsOffset, genericArgumentsCount).ToArray(); + var formattedTypes = currentTypeArguments.Select(t => FormatDisplayString(t, 0, t.GetGenericArguments())); + + // Standard generic types are displayed as Foo + displayName = $"{tokens[0]}<{string.Join(", ", formattedTypes)}>"; + + // Track the current offset for the shared generic arguments list + genericTypeOffset += genericArgumentsCount; + } + else + { + // Simple custom types + displayName = type.Name; + } + + // If the type is nested, recursively format the hierarchy as well + return type.IsNested + ? $"{FormatDisplayString(type.DeclaringType!, genericTypeOffset, typeArguments)}.{displayName}" + : $"{type.Namespace}.{displayName}"; + } + + // Atomically get or build the display string for the current type. + return DisplayNames.GetValue(type, t => + { + // By-ref types are displayed as T& + if (t.IsByRef) + { + t = t.GetElementType()!; + + return $"{FormatDisplayString(t, 0, t.GetGenericArguments())}&"; + } + + // Pointer types are displayed as T* + if (t.IsPointer) + { + var depth = 0; + + // Calculate the pointer indirection level + while (t.IsPointer) + { + depth++; + t = t.GetElementType()!; + } + + return $"{FormatDisplayString(t, 0, t.GetGenericArguments())}{new string('*', depth)}"; + } + + // Standard path for concrete types + return FormatDisplayString(t, 0, t.GetGenericArguments()); + }); + } +} diff --git a/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs b/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs new file mode 100644 index 0000000..54511d9 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Extensions/ValueTypeExtensions.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +/// Helpers for working with value types. +/// +public static class ValueTypeExtensions +{ + /// + /// Gets the table of hex characters (doesn't allocate, maps to .text section, see ). + /// + private static ReadOnlySpan HexCharactersTable => new[] + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', + (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'A', (byte)'B', + (byte)'C', (byte)'D', (byte)'E', (byte)'F' + }; + + /// + /// Returns a hexadecimal representation of a given value, left-padded and ordered as big-endian. + /// + /// The input type to format to . + /// The input value to format to . + /// + /// The hexadecimal representation of (with the '0x' prefix), left-padded to byte boundaries and ordered as big-endian. + /// + /// + /// As a byte (8 bits) is represented by two hexadecimal digits (each representing a group of 4 bytes), each + /// representation will always contain an even number of digits. For instance: + /// + /// Console.WriteLine(1.ToHexString()); // "0x01" + /// Console.WriteLine(((byte)255).ToHexString()); // "0xFF" + /// Console.WriteLine((-1).ToHexString()); // "0xFFFFFFFF" + /// + /// + public static unsafe string ToHexString(this T value) + where T : unmanaged + { + var sizeOfT = Unsafe.SizeOf(); + var bufferSize = (2 * sizeOfT) + 2; + var p = stackalloc char[bufferSize]; + + p[0] = '0'; + p[1] = 'x'; + + ref var rh = ref HexCharactersTable.DangerousGetPinnableReference(); + + for (int i = 0, j = bufferSize - 2; i < sizeOfT; i++, j -= 2) + { + var b = ((byte*)&value)[i]; + var low = b & 0x0F; + var high = (b & 0xF0) >> 4; + + p[j + 1] = (char)Unsafe.Add(ref rh, low); + p[j] = (char)Unsafe.Add(ref rh, high); + } + + return new(p, 0, bufferSize); + } +} diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.g.cs b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.g.cs new file mode 100644 index 0000000..cab243c --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.g.cs @@ -0,0 +1,1822 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// ===================== +// Auto generated file +// ===================== + +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +partial class Guard +{ + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(Span span, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(span, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(Span span, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithSpan(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(Span span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(span, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(Span source, Span destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(Span source, Span destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, destination, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, Span span, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)span.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, span, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, Span span, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)span.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, span, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(ReadOnlySpan span, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(span, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(ReadOnlySpan span, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(span, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ReadOnlySpan span, int size, [CallerArgumentExpression("span")] string name = "") + { + if (span.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(span, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ReadOnlySpan source, Span destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ReadOnlySpan source, Span destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, destination, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, ReadOnlySpan span, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)span.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, span, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, ReadOnlySpan span, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)span.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, span, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(Memory memory, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(memory, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(Memory memory, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty>(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(Memory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(memory, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(Memory source, Memory destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(Memory source, Memory destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, destination, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, Memory memory, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)memory.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, memory, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, Memory memory, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)memory.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, memory, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(ReadOnlyMemory memory, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(memory, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(ReadOnlyMemory memory, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty>(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(memory, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ReadOnlyMemory memory, int size, [CallerArgumentExpression("memory")] string name = "") + { + if (memory.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(memory, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ReadOnlyMemory source, Memory destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ReadOnlyMemory source, Memory destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, destination, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, ReadOnlyMemory memory, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)memory.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, memory, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, ReadOnlyMemory memory, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)memory.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, memory, name); + } + + /// + /// Asserts that the input array instance must be empty. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(T[] array, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(array, name); + } + + /// + /// Asserts that the input array instance must not be empty. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(T[] array, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty(name); + } + + /// + /// Asserts that the input array instance must have a size of a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(array, size, name); + } + + /// + /// Asserts that the input array instance must have a size not equal to a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(array, size, name); + } + + /// + /// Asserts that the input array instance must have a size over a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(array, size, name); + } + + /// + /// Asserts that the input array instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(array, size, name); + } + + /// + /// Asserts that the input array instance must have a size of less than a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(array, size, name); + } + + /// + /// Asserts that the input array instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input array instance. + /// The input array instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(T[] array, int size, [CallerArgumentExpression("array")] string name = "") + { + if (array.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(array, size, name); + } + + /// + /// Asserts that the source array instance must have the same size of a destination array instance. + /// + /// The item of items in the input array instance. + /// The source array instance to check the size for. + /// The destination array instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(T[] source, T[] destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination, name); + } + + /// + /// Asserts that the source array instance must have a size of less than or equal to that of a destination array instance. + /// + /// The item of items in the input array instance. + /// The source array instance to check the size for. + /// The destination array instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(T[] source, T[] destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, destination, name); + } + + /// + /// Asserts that the input index is valid for a given array instance. + /// + /// The item of items in the input array instance. + /// The input index to be used to access . + /// The input array instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, T[] array, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)array.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, array, name); + } + + /// + /// Asserts that the input index is not valid for a given array instance. + /// + /// The item of items in the input array instance. + /// The input index to be used to access . + /// The input array instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, T[] array, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)array.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, array, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(List list, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty((ICollection)list, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(List list, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty>(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo((ICollection)list, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo((ICollection)list, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan((ICollection)list, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo((ICollection)list, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan((ICollection)list, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(List list, int size, [CallerArgumentExpression("list")] string name = "") + { + if (list.Count <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo((ICollection)list, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(List source, List destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count == destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo((ICollection)source, destination.Count, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(List source, List destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count <= destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo((ICollection)source, destination.Count, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, List list, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)list.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, (ICollection)list, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, List list, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)list.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, (ICollection)list, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(ICollection collection, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(collection, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(ICollection collection, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty>(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ICollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(collection, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(ICollection source, ICollection destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count == destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination.Count, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(ICollection source, ICollection destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count <= destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination.Count, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, ICollection collection, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)collection.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, collection, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, ICollection collection, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)collection.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, collection, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(IReadOnlyCollection collection, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(collection, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(IReadOnlyCollection collection, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty>(name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(collection, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input instance. + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(IReadOnlyCollection collection, int size, [CallerArgumentExpression("collection")] string name = "") + { + if (collection.Count <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(collection, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(IReadOnlyCollection source, ICollection destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count == destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination.Count, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The item of items in the input instance. + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(IReadOnlyCollection source, ICollection destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.Count <= destination.Count) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, destination.Count, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, IReadOnlyCollection collection, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)collection.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, collection, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The item of items in the input instance. + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, IReadOnlyCollection collection, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)collection.Count) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, collection, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt new file mode 100644 index 0000000..4784e18 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Collection.tt @@ -0,0 +1,296 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +<#@include file="TypeInfo.ttinclude" #> +using System.Runtime.CompilerServices; + +namespace PerformanceFish.Utility.Diagnostics; + +/// +partial class Guard +{ +<# +GenerateTextForItems(EnumerableTypes, item => +{ +#> + /// + /// Asserts that the input <#=item.XmlType#> instance must be empty. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(<#=item.Cast#><#=item.Name#>, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must not be empty. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is == 0. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> != 0) + { + return; + } + +<# +if (item.Type == "Span") +{ +#> + ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithSpan(name); +<# +} +else if (item.Type == "ReadOnlySpan") +{ +#> + ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan(name); +<# +} +else +{ +#> + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty<<#=item.Type#>>(name); +<# +} +#> + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size of a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size not equal to a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size over a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size of at least or equal to a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size of less than a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the input <#=item.XmlType#> instance must have a size of less than or equal to a specified value. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input <#=item.XmlType#> instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, [CallerArgumentExpression("<#=item.Name#>")] string name = "") + { + if (<#=item.Name#>.<#=item.Size#> <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Cast#><#=item.Name#>, size, name); + } + + /// + /// Asserts that the source <#=item.XmlType#> instance must have the same size of a destination <#=item.XmlType#> instance. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The source <#=item.XmlType#> instance to check the size for. + /// The destination <#=item.XmlType#> instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.<#=item.Size#> == destination.<#=item.Size#>) + { + return; + } + +<# +if (item.HasCountProperty) +{ +#> + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#>source, destination.<#=item.Size#>, name); +<# +} +else +{ +#> + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(source, <#=item.Cast#>destination, name); +<# +} +#> + } + + /// + /// Asserts that the source <#=item.XmlType#> instance must have a size of less than or equal to that of a destination <#=item.XmlType#> instance. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The source <#=item.XmlType#> instance to check the size for. + /// The destination <#=item.XmlType#> instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, [CallerArgumentExpression("source")] string name = "") + { + if (source.<#=item.Size#> <= destination.<#=item.Size#>) + { + return; + } + +<# +if (item.HasCountProperty) +{ +#> + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Cast#>source, destination.<#=item.Size#>, name); +<# +} +else +{ +#> + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(source, <#=item.Cast#>destination, name); +<# +} +#> + } + + /// + /// Asserts that the input index is valid for a given <#=item.XmlType#> instance. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input index to be used to access . + /// The input <#=item.XmlType#> instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, <#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("index")] string name = "") + { +<# +// Here we're leveraging the fact that signed integers are represented +// in 2-complement to perform the bounds check with a single compare operation. +// This is the same trick used throughout CoreCLR as well. +// For more info and code sample, see the original conversation here: +// https://github.com/CommunityToolkit/WindowsCommunityToolkit/pull/3131#discussion_r390682835 +#> + if ((uint)index < (uint)<#=item.Name#>.<#=item.Size#>) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, <#=item.Cast#><#=item.Name#>, name); + } + + /// + /// Asserts that the input index is not valid for a given <#=item.XmlType#> instance. + /// + /// The item of items in the input <#=item.XmlType#> instance. + /// The input index to be used to access . + /// The input <#=item.XmlType#> instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, <#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)<#=item.Name#>.<#=item.Size#>) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, <#=item.Cast#><#=item.Name#>, name); + } +<# +}); +#> +} diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.g.cs b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.g.cs new file mode 100644 index 0000000..d8d48b7 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.g.cs @@ -0,0 +1,3528 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// ===================== +// Auto generated file +// ===================== + +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +partial class Guard +{ + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(byte value, byte target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(byte value, byte target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(byte value, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(byte value, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(byte value, byte minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(byte value, byte minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(byte value, byte minimum, byte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(sbyte value, sbyte target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(sbyte value, sbyte target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(sbyte value, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(sbyte value, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(sbyte value, sbyte minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(sbyte value, sbyte minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(sbyte value, sbyte minimum, sbyte maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(short value, short target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(short value, short target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(short value, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(short value, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(short value, short minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(short value, short minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(short value, short minimum, short maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(ushort value, ushort target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(ushort value, ushort target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(ushort value, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(ushort value, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(ushort value, ushort minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(ushort value, ushort minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(ushort value, ushort minimum, ushort maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(char value, char target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(char value, char target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(char value, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(char value, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(char value, char minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(char value, char minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(char value, char minimum, char maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(int value, int target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(int value, int target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(int value, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(int value, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(int value, int minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(int value, int minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(int value, int minimum, int maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(uint value, uint target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(uint value, uint target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(uint value, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(uint value, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(uint value, uint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(uint value, uint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(uint value, uint minimum, uint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(float value, float target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(float value, float target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(float value, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(float value, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(float value, float minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(float value, float minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(float value, float minimum, float maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(long value, long target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(long value, long target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(long value, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(long value, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(long value, long minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(long value, long minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(long value, long minimum, long maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(ulong value, ulong target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(ulong value, ulong target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(ulong value, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(ulong value, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(ulong value, ulong minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(ulong value, ulong minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(ulong value, ulong minimum, ulong maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(double value, double target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(double value, double target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(double value, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(double value, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(double value, double minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(double value, double minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(double value, double minimum, double maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(decimal value, decimal target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(decimal value, decimal target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(decimal value, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(decimal value, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(decimal value, decimal minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(decimal value, decimal minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(decimal value, decimal minimum, decimal maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(nint value, nint target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(nint value, nint target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(nint value, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(nint value, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(nint value, nint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(nint value, nint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(nint value, nint minimum, nint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(nuint value, nuint target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(nuint value, nuint target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(nuint value, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(nuint value, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(nuint value, nuint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(nuint value, nuint minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(nuint value, nuint minimum, nuint maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt new file mode 100644 index 0000000..23b4af2 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.Comparable.Numeric.tt @@ -0,0 +1,270 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +<#@include file="TypeInfo.ttinclude" #> +using System.Runtime.CompilerServices; + +namespace PerformanceFish.Utility.Diagnostics; + +/// +partial class Guard +{ +<# +GenerateTextForItems(NumericTypes, typeInfo => +{ +var (type, prefix) = typeInfo; +#> + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The target ="<#=type#>"/> value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "") + { + if (value == target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The target ="<#=type#>"/> value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "") + { + if (value != target) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The exclusive minimum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input ="<#=type#>"/> value to test. + /// The exclusive minimum ="<#=type#>"/> value that is accepted. + /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value > minimum && value < maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input ="<#=type#>"/> value to test. + /// The exclusive minimum ="<#=type#>"/> value that is accepted. + /// The exclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value <= minimum || value >= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value >= minimum && value <= maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The input ="<#=type#>"/> value to test. + /// The inclusive minimum ="<#=type#>"/> value that is accepted. + /// The inclusive maximum ="<#=type#>"/> value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(<#=type#> value, <#=type#> minimum, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "") + { + if (value < minimum || value > maximum) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } +<# +}); +#> +} diff --git a/Source/FisheryLib/Diagnostics/Generated/Guard.md b/Source/FisheryLib/Diagnostics/Generated/Guard.md new file mode 100644 index 0000000..b787eda --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/Guard.md @@ -0,0 +1,17 @@ +# T4 templates and generated APIs + +This folder contains a number of template files (with the `.tt` or `.ttinclude` extensions) and the generated `.g.cs` files generated by those templates. The template files use the T4 format, which is natively supported by Visual Studio (more info is available [here](https://docs.microsoft.com/visualstudio/modeling/code-generation-and-t4-text-templates)). + +## Why is this needed? + +There are a few reasons why T4 templates are used for the `Guard` class: + +- Especially when many overloads are available for an API, using templates makes it much easier to maintain code and spot mistakes, as the actual number of lines of code to review is much smaller: it's just the same code from each template! +- Using type-specific overloads instead of generic methods can result in faster code. For instance, T4 templates are used to generate overloads for comparison APIs (eg. `Guard.IsGreaterThan(int, int, string)`). This results in more compact and optimized code as opposed to a generic method using `where T : IComparable` as type constraint. +- In some cases, using generic methods just isn't possible. For instance, types like `Span` and `ReadOnlySpan` can't be used as generic type parameters, and even if that had been possible, they don't implement an interface we could use in the generic type constraint. Using T4 templates solves this issue, as we can just have specialized method for each supported type or collection type. + +## How to make changes + +If you need to change an API that is declared in a template, or to add a new one, just edit the right `.tt` file and save it: Visual Studio will take care of updating the generated `.g.cs` file automatically. Don't make changes to those generated `.g.cs` files directly, as those will be overwritten as soon as their source template is updated. + +Note that all the `.g.cs` files are checked in into the repository, so if you do make changes to a template file, make sure to also include the updated `.g.cs` file in your commits. diff --git a/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.g.cs b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.g.cs new file mode 100644 index 0000000..ec0fd7a --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.g.cs @@ -0,0 +1,810 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// ===================== +// Auto generated file +// ===================== + +using System.Diagnostics.CodeAnalysis; + +namespace FisheryLib.Utility.Diagnostics; + +/// +partial class Guard +{ + /// + partial class ThrowHelper + { + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(Span span, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(Span span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(Span source, Span destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(Span source, Span destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, Span span, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(span.Length)} to be a valid index for the target collection ({typeof(Span).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, Span span, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(span.Length)} to be an invalid index for the target collection ({typeof(Span).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(ReadOnlySpan span, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ReadOnlySpan span, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ReadOnlySpan source, Span destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ReadOnlySpan source, Span destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, ReadOnlySpan span, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(span.Length)} to be a valid index for the target collection ({typeof(ReadOnlySpan).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, ReadOnlySpan span, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(span.Length)} to be an invalid index for the target collection ({typeof(ReadOnlySpan).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(Memory memory, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(Memory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(Memory source, Memory destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(Memory source, Memory destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, Memory memory, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(memory.Length)} to be a valid index for the target collection ({typeof(Memory).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, Memory memory, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(memory.Length)} to be an invalid index for the target collection ({typeof(Memory).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(ReadOnlyMemory memory, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ReadOnlyMemory memory, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ReadOnlyMemory source, Memory destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ReadOnlyMemory source, Memory destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, ReadOnlyMemory memory, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(memory.Length)} to be a valid index for the target collection ({typeof(ReadOnlyMemory).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, ReadOnlyMemory memory, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(memory.Length)} to be an invalid index for the target collection ({typeof(ReadOnlyMemory).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(T[] array, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must be empty, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size over {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(T[] array, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(array.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(T[] source, T[] destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(T[] source, T[] destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(T[]).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, T[] array, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(array.Length)} to be a valid index for the target collection ({typeof(T[]).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, T[] array, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(array.Length)} to be an invalid index for the target collection ({typeof(T[]).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(List list, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must be empty, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size over {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(List list, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(list.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(List source, List destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(List source, List destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(List).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, List list, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(list.Count)} to be a valid index for the target collection ({typeof(List).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, List list, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(list.Count)} to be an invalid index for the target collection ({typeof(List).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(ICollection collection, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ICollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(ICollection source, ICollection destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(ICollection source, ICollection destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, ICollection collection, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(collection.Count)} to be a valid index for the target collection ({typeof(ICollection).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, ICollection collection, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(collection.Count)} to be an invalid index for the target collection ({typeof(ICollection).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(IReadOnlyCollection collection, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(IReadOnlyCollection collection, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(IReadOnlyCollection source, ICollection destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(IReadOnlyCollection source, ICollection destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, IReadOnlyCollection collection, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(collection.Count)} to be a valid index for the target collection ({typeof(IReadOnlyCollection).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, IReadOnlyCollection collection, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(collection.Count)} to be an invalid index for the target collection ({typeof(IReadOnlyCollection).ToTypeString()}), was {AssertString(index)}."); + } + } +} diff --git a/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt new file mode 100644 index 0000000..86e7aa1 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/ThrowHelper.Collection.tt @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +<#@include file="TypeInfo.ttinclude" #> +using System.Diagnostics.CodeAnalysis; + +namespace PerformanceFish.Utility.Diagnostics; + +/// +partial class Guard +{ + /// + partial class ThrowHelper + { +<# +GenerateTextForItems(EnumerableTypes, item => +{ +#> + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(<#=item.Type#> <#=item.Name#>, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must be empty, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Type#> <#=item.Name#>, int size, string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(<#=item.Name#>.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(<#=item.Type#> source, <#=item.DestinationType#> destination, string name) + { + throw new ArgumentException($"The source {AssertString(name)} ({typeof(<#=item.Type#>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.<#=item.Size#>)} (the destination), had a size of {AssertString(source.<#=item.Size#>)}.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, <#=item.Type#> <#=item.Name#>, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be a valid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}."); + } + + /// + /// Throws an when (or an overload) fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, <#=item.Type#> <#=item.Name#>, string name) + { + throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(<#=item.Name#>.<#=item.Size#>)} to be an invalid index for the target collection ({typeof(<#=item.Type#>).ToTypeString()}), was {AssertString(index)}."); + } +<# +}); +#> + } +} diff --git a/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude b/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude new file mode 100644 index 0000000..b2421dc --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Generated/TypeInfo.ttinclude @@ -0,0 +1,116 @@ +<#@ template language="C#"#> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".g.cs"#> +// ===================== +// Auto generated file +// ===================== +<#+ + /// + /// A model representing the info on an enumerable type + /// + sealed class EnumerableTypeInfo + { + public EnumerableTypeInfo( + string type, + string xmlType, + string name, + string size, + string destinationType, + string cast) + { + Type = type; + XmlType = xmlType; + Name = name; + Size = size; + DestinationType = destinationType; + Cast = cast; + } + + /// + /// Gets the name of the current type + /// + public string Type { get; } + + /// + /// Gets the XML-formatted name of the current type (eg. with {T} instead of <T>) + /// + public string XmlType { get; } + + /// + /// Gets the variable name to use + /// + public string Name { get; } + + /// + /// Gets the name of the property to use to retrieve the length of the current type + /// + public string Size { get; } + + /// + /// Gets whether or not the current type has a "Count" property + /// + public bool HasCountProperty => Size == "Count"; + + /// + /// Gets the name of the destination type, when comparing counts across different collections + /// + public string DestinationType { get; } + + /// + /// Gets the (optional) casting to resolve the diamond problem between different interfaces + /// + public string Cast { get; } + } + + /// + /// Gets the list of available enumerable types to generate APIs for + /// + static readonly IReadOnlyList EnumerableTypes = new[] + { + new EnumerableTypeInfo("Span", "", "span", "Length", "Span", ""), + new EnumerableTypeInfo("ReadOnlySpan", "", "span", "Length", "Span", ""), + new EnumerableTypeInfo("Memory", "", "memory", "Length", "Memory", ""), + new EnumerableTypeInfo("ReadOnlyMemory", "", "memory", "Length", "Memory", ""), + new EnumerableTypeInfo("T[]", " array", "array", "Length", "T[]", ""), + new EnumerableTypeInfo("List", "", "list", "Count", "List", "(ICollection)"), + new EnumerableTypeInfo("ICollection", "", "collection", "Count", "ICollection", ""), + new EnumerableTypeInfo("IReadOnlyCollection", "", "collection", "Count", "ICollection", ""), + }; + + /// + /// Gets the list of available numeric types to generate APIs for + /// + static readonly IReadOnlyList<(string Name, string Prefix)> NumericTypes = new[] + { + ("byte", "cref"), + ("sbyte", "cref"), + ("short", "cref"), + ("ushort", "cref"), + ("char", "cref"), + ("int", "cref"), + ("uint", "cref"), + ("float", "cref"), + ("long", "cref"), + ("ulong", "cref"), + ("double", "cref"), + ("decimal", "cref"), + ("nint", "langword"), + ("nuint", "langword") + }; + + /// + /// Generates text for a given sequence of items, automatically adding the necessary spacing + /// + void GenerateTextForItems(IReadOnlyList items, Action factory) + { + for (int i = 0; i < items.Count; i++) + { + // Insert a blank line after the first item + if (i > 0) WriteLine(""); + + // Invoke the factory with the current item + factory(items [i]); + } + } +#> \ No newline at end of file diff --git a/Source/FisheryLib/Diagnostics/Guard.Boolean.cs b/Source/FisheryLib/Diagnostics/Guard.Boolean.cs new file mode 100644 index 0000000..7d38f1e --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.Boolean.cs @@ -0,0 +1,356 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public static partial class Guard +{ + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsTrue([DoesNotReturnIf(false)] bool value, [CallerArgumentExpression("value")] string name = "") + { + if (value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsTrue(name); + } + + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// A message to display if is . + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsTrue([DoesNotReturnIf(false)] bool value, string name, string message) + { + if (value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsTrue(name, message); + } + + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsFalse([DoesNotReturnIf(true)] bool value, [CallerArgumentExpression("value")] string name = "") + { + if (!value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsFalse(name); + } + + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// A message to display if is . + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsFalse([DoesNotReturnIf(true)] bool value, string name, string message) + { + if (!value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsFalse(name, message); + } + +#if NET6_0_OR_GREATER + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// A message to display if is . + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsTrue([DoesNotReturnIf(false)] bool value, string name, [InterpolatedStringHandlerArgument("value")] ref IsTrueInterpolatedStringHandler message) + { + if (value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsTrue(name, message.ToStringAndClear()); + } + + /// + /// Asserts that the input value must be . + /// + /// The input to test. + /// The name of the input parameter being tested. + /// A message to display if is . + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsFalse([DoesNotReturnIf(true)] bool value, string name, [InterpolatedStringHandlerArgument("value")] ref IsFalseInterpolatedStringHandler message) + { + if (!value) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsFalse(name, message.ToStringAndClear()); + } + + /// + /// Provides an interpolated string handler for that only performs formatting if the assert fails. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [InterpolatedStringHandler] + public struct IsTrueInterpolatedStringHandler + { + /// + /// The handler used to perform the formatting. + /// + private StringBuilder.AppendInterpolatedStringHandler handler; + + /// + /// The underlying instance used by , if any. + /// + private StringBuilder? builder; + + /// + /// Creates an instance of the handler. + /// + /// The number of constant characters outside of interpolation expressions in the interpolated string. + /// The number of interpolation expressions in the interpolated string. + /// The condition passed to the method. + /// A value indicating whether formatting should proceed. + /// This is intended to be called only by compiler-generated code. Arguments are not validated as they'd otherwise be for members intended to be used directly. + public IsTrueInterpolatedStringHandler(int literalLength, int formattedCount, bool condition, out bool shouldAppend) + { + if (condition) + { + this.handler = default; + this.builder = null; + + shouldAppend = false; + } + else + { + StringBuilder builder = new(); + + this.handler = new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); + this.builder = builder; + + shouldAppend = true; + } + } + + /// + /// Extracts the built string from the handler. + /// + internal string ToStringAndClear() + { + string message = this.builder?.ToString() ?? string.Empty; + + this = default; + + return message; + } + + /// + public void AppendLiteral(string value) + { + this.handler.AppendLiteral(value); + } + + /// + public void AppendFormatted(T value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(T value, string? format) + { + this.handler.AppendFormatted(value, format); + } + + /// + public void AppendFormatted(T value, int alignment) + { + this.handler.AppendFormatted(value, alignment); + } + + /// + public void AppendFormatted(T value, int alignment, string? format) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(ReadOnlySpan value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(ReadOnlySpan value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(string? value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(string? value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(object? value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + } + + /// + /// Provides an interpolated string handler for that only performs formatting if the assert fails. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [InterpolatedStringHandler] + public struct IsFalseInterpolatedStringHandler + { + /// + /// The handler used to perform the formatting. + /// + private StringBuilder.AppendInterpolatedStringHandler handler; + + /// + /// The underlying instance used by , if any. + /// + private StringBuilder? builder; + + /// + /// Creates an instance of the handler. + /// + /// The number of constant characters outside of interpolation expressions in the interpolated string. + /// The number of interpolation expressions in the interpolated string. + /// The condition passed to the method. + /// A value indicating whether formatting should proceed. + /// This is intended to be called only by compiler-generated code. Arguments are not validated as they'd otherwise be for members intended to be used directly. + public IsFalseInterpolatedStringHandler(int literalLength, int formattedCount, bool condition, out bool shouldAppend) + { + if (!condition) + { + this.handler = default; + this.builder = null; + + shouldAppend = false; + } + else + { + StringBuilder builder = new(); + + this.handler = new StringBuilder.AppendInterpolatedStringHandler(literalLength, formattedCount, builder); + this.builder = builder; + + shouldAppend = true; + } + } + + /// + /// Extracts the built string from the handler. + /// + internal string ToStringAndClear() + { + string message = this.builder?.ToString() ?? string.Empty; + + this = default; + + return message; + } + + /// + public void AppendLiteral(string value) + { + this.handler.AppendLiteral(value); + } + + /// + public void AppendFormatted(T value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(T value, string? format) + { + this.handler.AppendFormatted(value, format); + } + + /// + public void AppendFormatted(T value, int alignment) + { + this.handler.AppendFormatted(value, alignment); + } + + /// + public void AppendFormatted(T value, int alignment, string? format) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(ReadOnlySpan value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(ReadOnlySpan value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(string? value) + { + this.handler.AppendFormatted(value); + } + + /// + public void AppendFormatted(string? value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + + /// + public void AppendFormatted(object? value, int alignment = 0, string? format = null) + { + this.handler.AppendFormatted(value, alignment, format); + } + } +#endif +} diff --git a/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs b/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs new file mode 100644 index 0000000..80c2ad3 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.Comparable.Generic.cs @@ -0,0 +1,439 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Asserts that the input value is . + /// + /// The type of value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is not . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsDefault(T value, [CallerArgumentExpression("value")] string name = "") + where T : struct, IEquatable + { + if (value.Equals(default)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsDefault(value, name); + } + + /// + /// Asserts that the input value is not . + /// + /// The type of value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotDefault(T value, [CallerArgumentExpression("value")] string name = "") + where T : struct, IEquatable + { + if (!value.Equals(default)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotDefault(name); + } + + /// + /// Asserts that the input value must be equal to a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is != . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IEquatable + { + if (value.Equals(target)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be not equal to a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is == . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IEquatable + { + if (!value.Equals(target)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name); + } + + /// + /// Asserts that the input value must be a bitwise match with a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is not a bitwise match for . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void IsBitwiseEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + where T : unmanaged + { + // Include some fast paths if the input type is of size 1, 2, 4, 8, or 16. + // In those cases, just reinterpret the bytes as values of an integer type, + // and compare them directly, which is much faster than having a loop over each byte. + // The conditional branches below are known at compile time by the JIT compiler, + // so that only the right one will actually be translated into native code. + if (sizeof(T) == 1) + { + var valueByte = Unsafe.As(ref value); + var targetByte = Unsafe.As(ref target); + + if (valueByte == targetByte) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + else if (sizeof(T) == 2) + { + var valueUShort = Unsafe.As(ref value); + var targetUShort = Unsafe.As(ref target); + + if (valueUShort == targetUShort) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + else if (sizeof(T) == 4) + { + var valueUInt = Unsafe.As(ref value); + var targetUInt = Unsafe.As(ref target); + + if (valueUInt == targetUInt) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + else if (sizeof(T) == 8) + { + var valueULong = Unsafe.As(ref value); + var targetULong = Unsafe.As(ref target); + + if (Bit64Compare(ref valueULong, ref targetULong)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + else if (sizeof(T) == 16) + { + var valueULong0 = Unsafe.As(ref value); + var targetULong0 = Unsafe.As(ref target); + + if (Bit64Compare(ref valueULong0, ref targetULong0)) + { + var valueULong1 = Unsafe.Add(ref Unsafe.As(ref value), 1); + var targetULong1 = Unsafe.Add(ref Unsafe.As(ref target), 1); + + if (Bit64Compare(ref valueULong1, ref targetULong1)) + { + return; + } + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + else + { + Span valueBytes = new(Unsafe.AsPointer(ref value), sizeof(T)); + Span targetBytes = new(Unsafe.AsPointer(ref target), sizeof(T)); + + if (valueBytes.SequenceEqual(targetBytes)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name); + } + } + + // Compares 64 bits of data from two given memory locations for bitwise equality + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe bool Bit64Compare(ref ulong left, ref ulong right) + { + // Handles 32 bit case, because using ulong is inefficient + if (sizeof(IntPtr) == 4) + { + ref var r0 = ref Unsafe.As(ref left); + ref var r1 = ref Unsafe.As(ref right); + + return r0 == r1 && + Unsafe.Add(ref r0, 1) == Unsafe.Add(ref r1, 1); + } + + return left == right; + } + + /// + /// Asserts that the input value must be less than a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThan(T value, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(maximum) < 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name); + } + + /// + /// Asserts that the input value must be less than or equal to a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsLessThanOrEqualTo(T value, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(maximum) <= 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name); + } + + /// + /// Asserts that the input value must be greater than a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThan(T value, T minimum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) > 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name); + } + + /// + /// Asserts that the input value must be greater than or equal to a specified value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < . + /// The method is generic to avoid boxing the parameters, if they are value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsGreaterThanOrEqualTo(T value, T minimum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) >= 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name); + } + + /// + /// Asserts that the input value must be in a given range. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or >= . + /// + /// This API asserts the equivalent of " in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRange(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) < 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given range. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or < . + /// + /// This API asserts the equivalent of " not in [, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRange(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) >= 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The type of input values to compare. + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is <= or >= . + /// + /// This API asserts the equivalent of " in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetween(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) > 0 && value.CompareTo(maximum) < 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The type of input values to compare. + /// The input value to test. + /// The exclusive minimum value that is accepted. + /// The exclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is > or < . + /// + /// This API asserts the equivalent of " not in (, )", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetween(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) <= 0 || value.CompareTo(maximum) >= 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must be in a given interval. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is < or > . + /// + /// This API asserts the equivalent of " in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsBetweenOrEqualTo(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) <= 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name); + } + + /// + /// Asserts that the input value must not be in a given interval. + /// + /// The type of input values to compare. + /// The input value to test. + /// The inclusive minimum value that is accepted. + /// The inclusive maximum value that is accepted. + /// The name of the input parameter being tested. + /// Thrown if is >= or <= . + /// + /// This API asserts the equivalent of " not in [, ]", using arithmetic notation. + /// The method is generic to avoid boxing the parameters, if they are value types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotBetweenOrEqualTo(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "") + where T : notnull, IComparable + { + if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) > 0) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs b/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs new file mode 100644 index 0000000..a208ad1 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.Comparable.Numeric.cs @@ -0,0 +1,213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Asserts that the input value must be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCloseTo(int value, int target, uint delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (uint)(value - target) : (uint)(target - value); + + if (difference <= delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must not be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCloseTo(int value, int target, uint delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (uint)(value - target) : (uint)(target - value); + + if (difference > delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCloseTo(long value, long target, ulong delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (ulong)(value - target) : (ulong)(target - value); + + if (difference <= delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must not be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCloseTo(long value, long target, ulong delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (ulong)(value - target) : (ulong)(target - value); + + if (difference > delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCloseTo(float value, float target, float delta, [CallerArgumentExpression("value")] string name = "") + { + if (Math.Abs(value - target) <= delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must not be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCloseTo(float value, float target, float delta, [CallerArgumentExpression("value")] string name = "") + { + if (Math.Abs(value - target) > delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCloseTo(double value, double target, double delta, [CallerArgumentExpression("value")] string name = "") + { + if (Math.Abs(value - target) <= delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must not be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCloseTo(double value, double target, double delta, [CallerArgumentExpression("value")] string name = "") + { + if (Math.Abs(value - target) > delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCloseTo(nint value, nint target, nuint delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (nuint)(value - target) : (nuint)(target - value); + + if (difference <= delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCloseTo(value, target, delta, name); + } + + /// + /// Asserts that the input value must not be within a given distance from a specified value. + /// + /// The input value to test. + /// The target value to test for. + /// The maximum distance to allow between and . + /// The name of the input parameter being tested. + /// Thrown if ( - ) <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCloseTo(nint value, nint target, nuint delta, [CallerArgumentExpression("value")] string name = "") + { + var difference = value >= target ? (nuint)(value - target) : (nuint)(target - value); + + if (difference > delta) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCloseTo(value, target, delta, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Guard.IO.cs b/Source/FisheryLib/Diagnostics/Guard.IO.cs new file mode 100644 index 0000000..e645849 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.IO.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Asserts that the input instance must support reading. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if doesn't support reading. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CanRead(Stream stream, [CallerArgumentExpression("stream")] string name = "") + { + if (stream.CanRead) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForCanRead(stream, name); + } + + /// + /// Asserts that the input instance must support writing. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if doesn't support writing. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CanWrite(Stream stream, [CallerArgumentExpression("stream")] string name = "") + { + if (stream.CanWrite) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForCanWrite(stream, name); + } + + /// + /// Asserts that the input instance must support seeking. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if doesn't support seeking. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CanSeek(Stream stream, [CallerArgumentExpression("stream")] string name = "") + { + if (stream.CanSeek) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForCanSeek(stream, name); + } + + /// + /// Asserts that the input instance must be at the starting position. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is not at the starting position. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsAtStartPosition(Stream stream, [CallerArgumentExpression("stream")] string name = "") + { + if (stream.Position == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsAtStartPosition(stream, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Guard.String.cs b/Source/FisheryLib/Diagnostics/Guard.String.cs new file mode 100644 index 0000000..ebbab5f --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.String.cs @@ -0,0 +1,334 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +#pragma warning disable CS8777 + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Asserts that the input instance must be or empty. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is neither nor empty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNullOrEmpty(string? text, [CallerArgumentExpression("text")] string name = "") + { + if (string.IsNullOrEmpty(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNullOrEmpty(text, name); + } + + /// + /// Asserts that the input instance must not be or empty. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is . + /// Thrown if is empty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotNullOrEmpty([NotNull] string? text, [CallerArgumentExpression("text")] string name = "") + { + if (!string.IsNullOrEmpty(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotNullOrEmpty(text, name); + } + + /// + /// Asserts that the input instance must be or whitespace. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is neither nor whitespace. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNullOrWhiteSpace(string? text, [CallerArgumentExpression("text")] string name = "") + { + if (string.IsNullOrWhiteSpace(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNullOrWhiteSpace(text, name); + } + + /// + /// Asserts that the input instance must not be or whitespace. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is . + /// Thrown if is whitespace. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotNullOrWhiteSpace([NotNull] string? text, [CallerArgumentExpression("text")] string name = "") + { + if (!string.IsNullOrWhiteSpace(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotNullOrWhiteSpace(text, name); + } + + /// + /// Asserts that the input instance must be empty. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is empty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsEmpty(string text, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length == 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsEmpty(text, name); + } + + /// + /// Asserts that the input instance must not be empty. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is empty. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotEmpty(string text, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length != 0) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotEmpty(name); + } + + /// + /// Asserts that the input instance must be whitespace. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is neither nor whitespace. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "") + { + if (string.IsNullOrWhiteSpace(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsWhiteSpace(text, name); + } + + /// + /// Asserts that the input instance must not be or whitespace. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is or whitespace. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "") + { + if (!string.IsNullOrWhiteSpace(text)) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotWhiteSpace(text, name); + } + + /// + /// Asserts that the input instance must have a size of a specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is != . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length == size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(text, size, name); + } + + /// + /// Asserts that the input instance must have a size not equal to a specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is == . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeNotEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length != size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeNotEqualTo(text, size, name); + } + + /// + /// Asserts that the input instance must have a size over a specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is <= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThan(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length > size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThan(text, size, name); + } + + /// + /// Asserts that the input instance must have a size of at least specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is < . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeGreaterThanOrEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length >= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(text, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than a specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is >= . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThan(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length < size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThan(text, size, name); + } + + /// + /// Asserts that the input instance must have a size of less than or equal to a specified value. + /// + /// The input instance to check the size for. + /// The target size to test. + /// The name of the input parameter being tested. + /// Thrown if the size of is > . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(string text, int size, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length <= size) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(text, size, name); + } + + /// + /// Asserts that the source instance must have the same size of a destination instance. + /// + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is != the one of . + /// The type is immutable, but the name of this API is kept for consistency with the other overloads. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeEqualTo(string text, string destination, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length == destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeEqualTo(text, destination, name); + } + + /// + /// Asserts that the source instance must have a size of less than or equal to that of a destination instance. + /// + /// The source instance to check the size for. + /// The destination instance to check the size for. + /// The name of the input parameter being tested. + /// Thrown if the size of is > the one of . + /// The type is immutable, but the name of this API is kept for consistency with the other overloads. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasSizeLessThanOrEqualTo(string text, string destination, [CallerArgumentExpression("text")] string name = "") + { + if (text.Length <= destination.Length) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(text, destination, name); + } + + /// + /// Asserts that the input index is valid for a given instance. + /// + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is not valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsInRangeFor(int index, string text, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index < (uint)text.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRangeFor(index, text, name); + } + + /// + /// Asserts that the input index is not valid for a given instance. + /// + /// The input index to be used to access . + /// The input instance to use to validate . + /// The name of the input parameter being tested. + /// Thrown if is valid to access . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotInRangeFor(int index, string text, [CallerArgumentExpression("index")] string name = "") + { + if ((uint)index >= (uint)text.Length) + { + return; + } + + ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(index, text, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Guard.Tasks.cs b/Source/FisheryLib/Diagnostics/Guard.Tasks.cs new file mode 100644 index 0000000..ee38611 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.Tasks.cs @@ -0,0 +1,184 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Asserts that the input instance is in a completed state. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is not in a completed state. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCompleted(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (task.IsCompleted) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCompleted(task, name); + } + + /// + /// Asserts that the input instance is not in a completed state. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is in a completed state. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCompleted(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (!task.IsCompleted) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCompleted(task, name); + } + + /// + /// Asserts that the input instance has been completed successfully. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if has not been completed successfully. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (task.Status == TaskStatus.RanToCompletion) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCompletedSuccessfully(task, name); + } + + /// + /// Asserts that the input instance has not been completed successfully. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if has been completed successfully. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (task.Status != TaskStatus.RanToCompletion) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCompletedSuccessfully(task, name); + } + + /// + /// Asserts that the input instance is faulted. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is not faulted. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsFaulted(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (task.IsFaulted) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsFaulted(task, name); + } + + /// + /// Asserts that the input instance is not faulted. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is faulted. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotFaulted(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (!task.IsFaulted) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotFaulted(task, name); + } + + /// + /// Asserts that the input instance is canceled. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is not canceled. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsCanceled(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (task.IsCanceled) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsCanceled(task, name); + } + + /// + /// Asserts that the input instance is not canceled. + /// + /// The input instance to test. + /// The name of the input parameter being tested. + /// Thrown if is canceled. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotCanceled(Task task, [CallerArgumentExpression("task")] string name = "") + { + if (!task.IsCanceled) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForIsNotCanceled(task, name); + } + + /// + /// Asserts that the input instance has a specific status. + /// + /// The input instance to test. + /// The task status that is accepted. + /// The name of the input parameter being tested. + /// Thrown if doesn't match . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasStatusEqualTo(Task task, TaskStatus status, [CallerArgumentExpression("task")] string name = "") + { + if (task.Status == status) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasStatusEqualTo(task, status, name); + } + + /// + /// Asserts that the input instance has not a specific status. + /// + /// The input instance to test. + /// The task status that is accepted. + /// The name of the input parameter being tested. + /// Thrown if matches . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void HasStatusNotEqualTo(Task task, TaskStatus status, [CallerArgumentExpression("task")] string name = "") + { + if (task.Status != status) + { + return; + } + + ThrowHelper.ThrowArgumentExceptionForHasStatusNotEqualTo(task, status, name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Guard.cs b/Source/FisheryLib/Diagnostics/Guard.cs new file mode 100644 index 0000000..a3aeff4 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Guard.cs @@ -0,0 +1,248 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +/// Helper methods to verify conditions when running code. +/// +[DebuggerStepThrough] +public static partial class Guard +{ + /// + /// Asserts that the input value is . + /// + /// The type of reference value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is not . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNull(T? value, [CallerArgumentExpression("value")] string name = "") + { + if (value is null) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNull(value, name); + } + + /// + /// Asserts that the input value is . + /// + /// The type of nullable value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is not . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNull(T? value, [CallerArgumentExpression("value")] string name = "") + where T : struct + { + if (value is null) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNull(value, name); + } + + /// + /// Asserts that the input value is not . + /// + /// The type of reference value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotNull([NotNull] T? value, [CallerArgumentExpression("value")] string name = "") + { + if (value is not null) + return; + + ThrowHelper.ThrowArgumentNullExceptionForIsNotNull(name); + } + + /// + /// Asserts that the input value is not . + /// + /// The type of nullable value type being tested. + /// The input value to test. + /// The name of the input parameter being tested. + /// Thrown if is . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotNull([NotNull] T? value, [CallerArgumentExpression("value")] string name = "") + where T : struct + { + if (value is not null) + return; + + ThrowHelper.ThrowArgumentNullExceptionForIsNotNull(name); + } + + /// + /// Asserts that the input value is of a specific type. + /// + /// The type of the input value. + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if is not of type . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsOfType(object value, [CallerArgumentExpression("value")] string name = "") + { + if (value.GetType() == typeof(T)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsOfType(value, name); + } + + /// + /// Asserts that the input value is not of a specific type. + /// + /// The type of the input value. + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if is of type . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotOfType(object value, [CallerArgumentExpression("value")] string name = "") + { + if (value.GetType() != typeof(T)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNotOfType(value, name); + } + + /// + /// Asserts that the input value is of a specific type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if the type of is not the same as . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsOfType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + { + if (value.GetType() == type) + return; + + ThrowHelper.ThrowArgumentExceptionForIsOfType(value, type, name); + } + + /// + /// Asserts that the input value is not of a specific type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if the type of is the same as . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotOfType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + { + if (value.GetType() != type) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNotOfType(value, type, name); + } + + /// + /// Asserts that the input value can be assigned to a specified type. + /// + /// The type to check the input value against. + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if can't be assigned to type . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsAssignableToType(object value, [CallerArgumentExpression("value")] string name = "") + { + if (value is T) + return; + + ThrowHelper.ThrowArgumentExceptionForIsAssignableToType(value, name); + } + + /// + /// Asserts that the input value can't be assigned to a specified type. + /// + /// The type to check the input value against. + /// The input to test. + /// The name of the input parameter being tested. + /// Thrown if can be assigned to type . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotAssignableToType(object value, [CallerArgumentExpression("value")] string name = "") + { + if (value is not T) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNotAssignableToType(value, name); + } + + /// + /// Asserts that the input value can be assigned to a specified type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if can't be assigned to . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsAssignableToType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + { + if (type.IsInstanceOfType(value)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsAssignableToType(value, type, name); + } + + /// + /// Asserts that the input value can't be assigned to a specified type. + /// + /// The input to test. + /// The type to look for. + /// The name of the input parameter being tested. + /// Thrown if can be assigned to . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsNotAssignableToType(object value, Type type, [CallerArgumentExpression("value")] string name = "") + { + if (!type.IsInstanceOfType(value)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsNotAssignableToType(value, type, name); + } + + /// + /// Asserts that the input value must be the same instance as the target value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is not the same instance as . + /// The method is generic to prevent using it with value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsReferenceEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + where T : class + { + if (ReferenceEquals(value, target)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsReferenceEqualTo(name); + } + + /// + /// Asserts that the input value must not be the same instance as the target value. + /// + /// The type of input values to compare. + /// The input value to test. + /// The target value to test for. + /// The name of the input parameter being tested. + /// Thrown if is the same instance as . + /// The method is generic to prevent using it with value types. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void IsReferenceNotEqualTo(T value, T target, [CallerArgumentExpression("value")] string name = "") + where T : class + { + if (!ReferenceEquals(value, target)) + return; + + ThrowHelper.ThrowArgumentExceptionForIsReferenceNotEqualTo(name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs new file mode 100644 index 0000000..4d13d6d --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Collection.Generic.ThrowHelper.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + /// The item of items in the input instance. + /// This method is needed because can't be used as a generic type parameter. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotEmptyWithSpan(string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span).ToTypeString()}) must not be empty.", name); + } + + /// + /// Throws an when fails. + /// + /// The item of items in the input instance. + /// This method is needed because can't be used as a generic type parameter. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan(string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan).ToTypeString()}) must not be empty.", name); + } + + /// + /// Throws an when (or an overload) fails. + /// + /// The item of items in the input collection. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotEmpty(string name) + { + throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be empty.", name); + } + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs new file mode 100644 index 0000000..2264eba --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Generic.ThrowHelper.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + /// The type of value type being tested. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsDefault(T value, string name) + where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the default value {AssertString(default(T))}, was {AssertString(value)}.", name); + + /// + /// Throws an when fails. + /// + /// The type of value type being tested. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotDefault(string name) + where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the default value {AssertString(default(T))}.", name); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEqualTo(T value, T target, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be equal to {AssertString(target)}, was {AssertString(value)}.", name); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotEqualTo(T value, T target, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be equal to {AssertString(target)}, was {AssertString(value)}.", name); + + /// + /// Throws an when fails. + /// + /// The type of input values being compared. + [DoesNotReturn] + public static void ThrowArgumentExceptionForBitwiseEqualTo(T value, T target, string name) + where T : unmanaged => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) is not a bitwise match, was <{value.ToHexString()}> instead of <{target.ToHexString()}>.", name); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsLessThan(T value, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(T value, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be less than or equal to {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThan(T value, T minimum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than {AssertString(minimum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(T value, T minimum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be greater than or equal to {AssertString(minimum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRange(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRange(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be in the range given by {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsBetween(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotBetween(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + + /// + /// Throws an when fails. + /// + /// The type of values being tested. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(T value, T minimum, T maximum, string name) => throw new ArgumentOutOfRangeException(name, value!, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be between or equal to {AssertString(minimum)} and {AssertString(maximum)}, was {AssertString(value)}."); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs new file mode 100644 index 0000000..4810078 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Comparable.Numeric.ThrowHelper.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCloseTo(int value, int target, uint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCloseTo(int value, int target, uint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(int).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((double)((long)value - target)))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCloseTo(long value, long target, ulong delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCloseTo(long value, long target, ulong delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(long).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs((decimal)value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCloseTo(float value, float target, float delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCloseTo(float value, float target, float delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(float).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCloseTo(double value, double target, double delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCloseTo(double value, double target, double delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(double).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCloseTo(nint value, nint target, nuint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCloseTo(nint value, nint target, nuint delta, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(nint).ToTypeString()}) must not be within a distance of {AssertString(delta)} from {AssertString(target)}, was {AssertString(value)} and had a distance of {AssertString(Math.Abs(value - target))}.", name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs new file mode 100644 index 0000000..9053433 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.IO.ThrowHelper.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForCanRead(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support reading.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForCanWrite(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support writing.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForCanSeek(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support seeking.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsAtStartPosition(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) must be at position {AssertString(0)}, was at {AssertString(stream.Position)}.", name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs new file mode 100644 index 0000000..0ff9c6e --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.String.ThrowHelper.cs @@ -0,0 +1,158 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNullOrEmpty(string? text, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or empty, was {AssertString(text)}.", name); + + /// + /// Throws an or when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotNullOrEmpty(string? text, string name) + { + [MethodImpl(MethodImplOptions.NoInlining)] + static Exception GetException(string? text, string name) + => text is null + ? new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or empty, was null.") + : new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or empty, was empty.", name); + + throw GetException(text, name); + } + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNullOrWhiteSpace(string? text, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be null or whitespace, was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotNullOrWhiteSpace(string? text, string name) + { + [MethodImpl(MethodImplOptions.NoInlining)] + static Exception GetException(string? text, string name) + => text is null + ? new ArgumentNullException(name, $"Parameter {AssertString(name)} (string) must not be null or whitespace, was null.") + : new ArgumentException($"Parameter {AssertString(name)} (string) must not be null or whitespace, was whitespace.", name); + + throw GetException(text, name); + } + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsEmpty(string text, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be empty, was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotEmpty(string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be empty.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsWhiteSpace(string text, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must be whitespace, was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotWhiteSpace(string text, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be whitespace, was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeNotEqualTo(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must not have a size equal to {size}, was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThan(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size over {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size of at least {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThan(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string text, int size, string name) + => throw new ArgumentException($"Parameter {AssertString(name)} (string) must have a size less than or equal to {size}, had a size of {text.Length} and was {AssertString(text)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeEqualTo(string source, string destination, string name) + => throw new ArgumentException($"The source {AssertString(name)} (string) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo(string source, string destination, string name) + => throw new ArgumentException($"The source {AssertString(name)} (string) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor(int index, string text, string name) + => throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must be in the range given by <0> and {AssertString(text.Length)} to be a valid index for the target string, was {AssertString(index)}."); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor(int index, string text, string name) + => throw new ArgumentOutOfRangeException(name, index, $"Parameter {AssertString(name)} (int) must not be in the range given by <0> and {AssertString(text.Length)} to be an invalid index for the target string, was {AssertString(index)}."); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs new file mode 100644 index 0000000..4f46fab --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.Tasks.ThrowHelper.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + private partial class ThrowHelper + { + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCompleted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCompleted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCompletedSuccessfully(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be completed successfully, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCompletedSuccessfully(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be completed successfully, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsFaulted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be faulted, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotFaulted(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be faulted, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsCanceled(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must be canceled, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotCanceled(Task task, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not be canceled, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasStatusEqualTo(Task task, TaskStatus status, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must have status {status}, had status {AssertString(task.Status)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForHasStatusNotEqualTo(Task task, TaskStatus status, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({task.GetType().ToTypeString()}) must not have status {AssertString(status)}.", name); + } +} diff --git a/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs b/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs new file mode 100644 index 0000000..df45c9b --- /dev/null +++ b/Source/FisheryLib/Diagnostics/Internals/Guard.ThrowHelper.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public partial class Guard +{ + /// + /// Helper methods to efficiently throw exceptions. + /// + private static partial class ThrowHelper + { + /// + /// Returns a formatted representation of the input value. + /// + /// The input to format. + /// A formatted representation of to display in error messages. + private static string AssertString(object? obj) + => obj switch + { + string _ => $"\"{obj}\"", + null => "null", + _ => $"<{obj}>" + }; + + /// + /// Throws an when (where is ) fails. + /// + /// The type of the input value. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNull(T value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be null, was {AssertString(value)} ({value!.GetType().ToTypeString()}).", name); + + /// + /// Throws an when (where is ) fails. + /// + /// The type of the input value. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNull(T? value, string name) + where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T?).ToTypeString()}) must be null, was {AssertString(value)} ({typeof(T).ToTypeString()}).", name); + + /// + /// Throws an when fails. + /// + /// The type of the input value. + [DoesNotReturn] + public static void ThrowArgumentNullExceptionForIsNotNull(string name) => throw new ArgumentNullException(name, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be not null)."); + + /// + /// Throws an when fails. + /// + /// The type of the input value. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsOfType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + /// The type of the input value. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotOfType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsOfType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotOfType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + /// The type being checked against. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsAssignableToType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + /// The type being checked against. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsAssignableToType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsNotAssignableToType(object value, Type type, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {type.ToTypeString()}, was {value.GetType().ToTypeString()}.", name); + + /// + /// Throws an when fails. + /// + /// The type of input value being compared. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsReferenceEqualTo(string name) + where T : class => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the same instance as the target object.", name); + + /// + /// Throws an when fails. + /// + /// The type of input value being compared. + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsReferenceNotEqualTo(string name) + where T : class => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the same instance as the target object.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsTrue(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsTrue(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false: {AssertString(message)}.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsFalse(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true.", name); + + /// + /// Throws an when fails. + /// + [DoesNotReturn] + public static void ThrowArgumentExceptionForIsFalse(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true: {AssertString(message)}.", name); + } +} diff --git a/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs b/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs new file mode 100644 index 0000000..e04a2b7 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/ThrowHelper.Generic.cs @@ -0,0 +1,843 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +namespace FisheryLib.Utility.Diagnostics; + +/// +public static partial class ThrowHelper +{ + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArrayTypeMismatchException() => throw new ArrayTypeMismatchException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArrayTypeMismatchException(string? message) => throw new ArrayTypeMismatchException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArrayTypeMismatchException(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentException() => throw new ArgumentException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentException(string? message) => throw new ArgumentException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentException(string? message, Exception? innerException) => throw new ArgumentException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentException(string? name, string? message) => throw new ArgumentException(message, name); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentException(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentNullException() => throw new ArgumentNullException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentNullException(string? name) => throw new ArgumentNullException(name); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentNullException(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentNullException(string? name, string? message) => throw new ArgumentNullException(name, message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentOutOfRangeException(string? name) => throw new ArgumentOutOfRangeException(name); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentOutOfRangeException(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentOutOfRangeException(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The current argument value. + /// The message to include in the exception. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowArgumentOutOfRangeException(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowCOMException() => throw new COMException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowCOMException(string? message) => throw new COMException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowCOMException(string? message, Exception? innerException) => throw new COMException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The HRESULT of the error to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowCOMException(string? message, int error) => throw new COMException(message, error); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowExternalException() => throw new ExternalException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowExternalException(string? message) => throw new ExternalException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowExternalException(string? message, Exception? innerException) => throw new ExternalException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The argument name. + /// The HRESULT of the error to include. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowExternalException(string? message, int error) => throw new ExternalException(message, error); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowFormatException() => throw new FormatException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowFormatException(string? message) => throw new FormatException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowFormatException(string? message, Exception? innerException) => throw new FormatException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInsufficientMemoryException() => throw new InsufficientMemoryException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInsufficientMemoryException(string? message) => throw new InsufficientMemoryException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInsufficientMemoryException(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidDataException() => throw new InvalidDataException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidDataException(string? message) => throw new InvalidDataException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidDataException(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidOperationException() => throw new InvalidOperationException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidOperationException(string? message) => throw new InvalidOperationException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowInvalidOperationException(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowLockRecursionException() => throw new LockRecursionException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowLockRecursionException(string? message) => throw new LockRecursionException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowLockRecursionException(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingFieldException() => throw new MissingFieldException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingFieldException(string? message) => throw new MissingFieldException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingFieldException(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The target class being inspected. + /// The target field being retrieved. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingFieldException(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMemberException() => throw new MissingMemberException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMemberException(string? message) => throw new MissingMemberException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMemberException(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The target class being inspected. + /// The target member being retrieved. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMemberException(string? className, string? memberName) => throw new MissingMemberException(className, memberName); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMethodException() => throw new MissingMethodException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMethodException(string? message) => throw new MissingMethodException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMethodException(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The target class being inspected. + /// The target method being retrieved. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowMissingMethodException(string? className, string? methodName) => throw new MissingMethodException(className, methodName); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowNotSupportedException() => throw new NotSupportedException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowNotSupportedException(string? message) => throw new NotSupportedException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowNotSupportedException(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The name of the disposed object. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowObjectDisposedException(string? objectName) => throw new ObjectDisposedException(objectName); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The name of the disposed object. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowObjectDisposedException(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The name of the disposed object. + /// The message to include in the exception. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowObjectDisposedException(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException() => throw new OperationCanceledException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException(string? message) => throw new OperationCanceledException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The in use. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException(CancellationToken token) => throw new OperationCanceledException(token); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The in use. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException(string? message, CancellationToken token) => throw new OperationCanceledException(message, token); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// The in use. + /// Thrown with the specified parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowOperationCanceledException(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowPlatformNotSupportedException() => throw new PlatformNotSupportedException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowPlatformNotSupportedException(string? message) => throw new PlatformNotSupportedException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowPlatformNotSupportedException(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowSynchronizationLockException() => throw new SynchronizationLockException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowSynchronizationLockException(string? message) => throw new SynchronizationLockException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowSynchronizationLockException(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowTimeoutException() => throw new TimeoutException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowTimeoutException(string? message) => throw new TimeoutException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowTimeoutException(string? message, Exception? innerException) => throw new TimeoutException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowUnauthorizedAccessException() => throw new UnauthorizedAccessException(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowUnauthorizedAccessException(string? message) => throw new UnauthorizedAccessException(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowUnauthorizedAccessException(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// Thrown with no parameters. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowWin32Exception() => throw new Win32Exception(); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The Win32 error code associated with this exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowWin32Exception(int error) => throw new Win32Exception(error); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The Win32 error code associated with this exception. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowWin32Exception(int error, string? message) => throw new Win32Exception(error, message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowWin32Exception(string? message) => throw new Win32Exception(message); + + /// + /// Throws a new . + /// + /// The type of expected result. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + /// This method always throws, so it actually never returns a value. + [DoesNotReturn] + public static T ThrowWin32Exception(string? message, Exception? innerException) => throw new Win32Exception(message, innerException); +} diff --git a/Source/FisheryLib/Diagnostics/ThrowHelper.cs b/Source/FisheryLib/Diagnostics/ThrowHelper.cs new file mode 100644 index 0000000..5a7f795 --- /dev/null +++ b/Source/FisheryLib/Diagnostics/ThrowHelper.cs @@ -0,0 +1,683 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +namespace FisheryLib.Utility.Diagnostics; + +/// +/// Helper methods to efficiently throw exceptions. +/// +public static partial class ThrowHelper +{ + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowArrayTypeMismatchException() => throw new ArrayTypeMismatchException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowArrayTypeMismatchException(string? message) => throw new ArrayTypeMismatchException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArrayTypeMismatchException(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowArgumentException() => throw new ArgumentException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowArgumentException(string? message) => throw new ArgumentException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentException(string? message, Exception? innerException) => throw new ArgumentException(message, innerException); + + /// + /// Throws a new . + /// + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentException(string? name, string? message) => throw new ArgumentException(message, name); + + /// + /// Throws a new . + /// + /// The argument name. + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentException(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowArgumentNullException() => throw new ArgumentNullException(); + + /// + /// Throws a new . + /// + /// The argument name. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowArgumentNullException(string? name) => throw new ArgumentNullException(name); + + /// + /// Throws a new . + /// + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentNullException(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException); + + /// + /// Throws a new . + /// + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentNullException(string? name, string? message) => throw new ArgumentNullException(name, message); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); + + /// + /// Throws a new . + /// + /// The argument name. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException(string? name) => throw new ArgumentOutOfRangeException(name); + + /// + /// Throws a new . + /// + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException); + + /// + /// Throws a new . + /// + /// The argument name. + /// The message to include in the exception. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message); + + /// + /// Throws a new . + /// + /// The argument name. + /// The current argument value. + /// The message to include in the exception. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowArgumentOutOfRangeException(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowCOMException() => throw new COMException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowCOMException(string? message) => throw new COMException(message); + + /// + /// Throws a new . + /// + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowCOMException(string? message, Exception? innerException) => throw new COMException(message, innerException); + + /// + /// Throws a new . + /// + /// The argument name. + /// The HRESULT of the error to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowCOMException(string? message, int error) => throw new COMException(message, error); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowExternalException() => throw new ExternalException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowExternalException(string? message) => throw new ExternalException(message); + + /// + /// Throws a new . + /// + /// The argument name. + /// The inner to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowExternalException(string? message, Exception? innerException) => throw new ExternalException(message, innerException); + + /// + /// Throws a new . + /// + /// The argument name. + /// The HRESULT of the error to include. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowExternalException(string? message, int error) => throw new ExternalException(message, error); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowFormatException() => throw new FormatException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowFormatException(string? message) => throw new FormatException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowFormatException(string? message, Exception? innerException) => throw new FormatException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowInsufficientMemoryException() => throw new InsufficientMemoryException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInsufficientMemoryException(string? message) => throw new InsufficientMemoryException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInsufficientMemoryException(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowInvalidDataException() => throw new InvalidDataException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInvalidDataException(string? message) => throw new InvalidDataException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInvalidDataException(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowInvalidOperationException() => throw new InvalidOperationException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInvalidOperationException(string? message) => throw new InvalidOperationException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowInvalidOperationException(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowLockRecursionException() => throw new LockRecursionException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowLockRecursionException(string? message) => throw new LockRecursionException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowLockRecursionException(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowMissingFieldException() => throw new MissingFieldException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingFieldException(string? message) => throw new MissingFieldException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingFieldException(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException); + + /// + /// Throws a new . + /// + /// The target class being inspected. + /// The target field being retrieved. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowMissingFieldException(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowMissingMemberException() => throw new MissingMemberException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingMemberException(string? message) => throw new MissingMemberException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingMemberException(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException); + + /// + /// Throws a new . + /// + /// The target class being inspected. + /// The target member being retrieved. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowMissingMemberException(string? className, string? memberName) => throw new MissingMemberException(className, memberName); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowMissingMethodException() => throw new MissingMethodException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingMethodException(string? message) => throw new MissingMethodException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowMissingMethodException(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException); + + /// + /// Throws a new . + /// + /// The target class being inspected. + /// The target method being retrieved. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowMissingMethodException(string? className, string? methodName) => throw new MissingMethodException(className, methodName); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowNotSupportedException() => throw new NotSupportedException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowNotSupportedException(string? message) => throw new NotSupportedException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowNotSupportedException(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException); + + /// + /// Throws a new . + /// + /// The name of the disposed object. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowObjectDisposedException(string? objectName) => throw new ObjectDisposedException(objectName); + + /// + /// Throws a new . + /// + /// The name of the disposed object. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowObjectDisposedException(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException); + + /// + /// Throws a new . + /// + /// The name of the disposed object. + /// The message to include in the exception. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowObjectDisposedException(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowOperationCanceledException() => throw new OperationCanceledException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowOperationCanceledException(string? message) => throw new OperationCanceledException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowOperationCanceledException(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException); + + /// + /// Throws a new . + /// + /// The in use. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowOperationCanceledException(CancellationToken token) => throw new OperationCanceledException(token); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The in use. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowOperationCanceledException(string? message, CancellationToken token) => throw new OperationCanceledException(message, token); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// The in use. + /// Thrown with the specified parameters. + [DoesNotReturn] + public static void ThrowOperationCanceledException(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowPlatformNotSupportedException() => throw new PlatformNotSupportedException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowPlatformNotSupportedException(string? message) => throw new PlatformNotSupportedException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowPlatformNotSupportedException(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowSynchronizationLockException() => throw new SynchronizationLockException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowSynchronizationLockException(string? message) => throw new SynchronizationLockException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowSynchronizationLockException(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowTimeoutException() => throw new TimeoutException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowTimeoutException(string? message) => throw new TimeoutException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowTimeoutException(string? message, Exception? innerException) => throw new TimeoutException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowUnauthorizedAccessException() => throw new UnauthorizedAccessException(); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowUnauthorizedAccessException(string? message) => throw new UnauthorizedAccessException(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowUnauthorizedAccessException(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException); + + /// + /// Throws a new . + /// + /// Thrown with no parameters. + [DoesNotReturn] + public static void ThrowWin32Exception() => throw new Win32Exception(); + + /// + /// Throws a new . + /// + /// The Win32 error code associated with this exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowWin32Exception(int error) => throw new Win32Exception(error); + + /// + /// Throws a new . + /// + /// The Win32 error code associated with this exception. + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowWin32Exception(int error, string? message) => throw new Win32Exception(error, message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowWin32Exception(string? message) => throw new Win32Exception(message); + + /// + /// Throws a new . + /// + /// The message to include in the exception. + /// The inner to include. + /// Thrown with the specified parameter. + [DoesNotReturn] + public static void ThrowWin32Exception(string? message, Exception? innerException) => throw new Win32Exception(message, innerException); +} diff --git a/Source/FisheryLib/Equality.cs b/Source/FisheryLib/Equality.cs new file mode 100644 index 0000000..fe90726 --- /dev/null +++ b/Source/FisheryLib/Equality.cs @@ -0,0 +1,29 @@ +// /* Copyright (c) 2022 bradson +// * This Source Code Form is subject to the terms of the Mozilla Public +// * License, v. 2.0. If a copy of the MPL was not distributed with this +// * file, You can obtain one at https://mozilla.org/MPL/2.0/. +// */ + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace FisheryLib; + +public static class Equality +{ + /// + /// Generic overload of Equals to avoid boxing. Makes use of function pointers for best performance and does not throw on null for reference types. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool Equals([AllowNull] this T @this, [AllowNull] T other) + => FunctionPointers.Equals.Default(@this!, other!); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool Equals([AllowNull] this ref T @this, [AllowNull] ref T other) + where T : struct // required by the compiler for 'this ref' + => FunctionPointers.EqualsByRef.Default(ref @this!, ref other!); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool EqualsByRef([AllowNull] ref T @this, [AllowNull] ref T other) + => FunctionPointers.EqualsByRef.Default(ref @this!, ref other!); +} \ No newline at end of file diff --git a/Source/FisheryLib/FishPatch.cs b/Source/FisheryLib/FishPatch.cs new file mode 100644 index 0000000..c33ba8b --- /dev/null +++ b/Source/FisheryLib/FishPatch.cs @@ -0,0 +1,338 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +/*using System.Collections; +using System.Linq; +using System.Linq.Expressions; +using Verse; + +namespace FisheryLib; + +internal class FishPatchManager +{ + internal const string FISHERY = "fishery"; + + internal FishPatchManager(Assembly assembly) + { + Assembly = assembly; + ModContentPack = LoadedModManager.RunningModsListForReading.Find(pack => pack.assemblies.loadedAssemblies.Contains(assembly)); + ModName = ModContentPack?.Name ?? assembly.GetName().Name; + ModPackageID = ModContentPack?.PackageIdPlayerFacing; + Harmony = new($"{FISHERY}.{ModPackageID ?? ModName.ToLowerInvariant()}"); + + } + + public Assembly Assembly { get; } + public ModContentPack? ModContentPack { get; } + public string? ModPackageID { get; } + public string ModName { get; } + public Harmony Harmony { get; } +} + +public abstract class FishPatch : IExposable, IHasDescription +{ + public string ModName = "Fishery"; + public Harmony Harmony { get; } = new("bs.fishery"); + public void PatchAll() + { + foreach (var patch in AllPatchClasses) + { + try + { + if (!patch.RequiresLoadedGameForPatching) + patch.Patches.PatchAll(); + } + catch (Exception ex) + { + Log.Error($"{ModName} encountered an exception while patching:\n{ex}"); + } + } + } + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + if (value) + { + if (ShouldBePatched) + TryPatch(); + } + else + { + var shouldBePatched = ShouldBePatched; + TryUnpatch(); + ShouldBePatched = shouldBePatched; + } + } + } + private bool _enabled = true; + public virtual bool DefaultState => true; + public virtual int PrefixMethodPriority => TryGetPriority(PrefixMethodInfo); + public virtual int PostfixMethodPriority => TryGetPriority(PostfixMethodInfo); + public virtual int TranspilerMethodPriority => TryGetPriority(TranspilerMethodInfo); + public virtual int FinalizerMethodPriority => TryGetPriority(FinalizerMethodInfo); + public MethodInfo? HarmonyMethodInfo { get; private set; } + private bool Patched { get; set; } + private bool ShouldBePatched { get; set; } + + public virtual string Name => GetType().Name; + public virtual string? Description => null; + public virtual bool ShowSettings => true; + + public virtual Delegate? TargetMethodGroup => null; + public virtual IEnumerable? TargetMethodGroups => null; + public virtual Expression? TargetMethod => null; + public virtual IEnumerable>? TargetMethods => null; + public virtual MethodBase TargetMethodInfo => TargetMethod != null ? SymbolExtensions.GetMethodInfo(TargetMethod) + : TargetMethodGroup?.Method ?? throw new MissingMethodException(GetType().ToString()); + public virtual IEnumerable TargetMethodInfos => TargetMethods?.Select(m => SymbolExtensions.GetMethodInfo(m)) + ?? TargetMethodGroups?.Select(m => m.Method) ?? (TargetMethodInfo != null ? new MethodBase[] { TargetMethodInfo }.AsEnumerable() : throw new MissingMethodException(GetType().ToString())); + public virtual MethodInfo ReversePatchMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "REVERSEPATCH" || (m.HasAttribute() && !m.HasAttribute())); + public virtual MethodInfo ReversePatchTranspilerMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "REVERSEPATCHTRANSPILER" || (m.HasAttribute() && m.HasAttribute())); + public virtual MethodInfo PrefixMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "PREFIX" || m.HasAttribute()); + public virtual MethodInfo PostfixMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "POSTFIX" || m.HasAttribute()); + public virtual MethodInfo TranspilerMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "TRANSPILER" || (m.HasAttribute() && !m.HasAttribute())); + public virtual MethodInfo FinalizerMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "FINALIZER" || m.HasAttribute()); + public virtual MethodInfo PrepareMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "PREPARE" || m.HasAttribute()); + public virtual MethodInfo CleanupMethodInfo => GetType().GetMethods(AccessTools.allDeclared) + .FirstOrDefault(m => m.Name.ToUpperInvariant() == "CLEANUP" || m.HasAttribute()); + + public FishPatch() => _enabled = DefaultState; + + public virtual MethodInfo? TryPatch() + { + if (TargetMethodInfos is null || !TargetMethodInfos.Any()) + { + Log.Error($"Tried to apply patches for {GetType().Name}, but it lacks a target method for patching."); + return null; + } + if (PrefixMethodInfo is null && PostfixMethodInfo is null && TranspilerMethodInfo is null && FinalizerMethodInfo is null && ReversePatchMethodInfo is null) + { + Log.Error($"Tried to apply patches for {GetType().Name}, but there are none. This is likely not intended."); + return null; + } + + ShouldBePatched = true; + if (Enabled && !Patched) + { + Patched = true; + + PrepareMethodInfo?.Invoke(null, null); + foreach (var method in TargetMethodInfos) + { + try + { + if (ReversePatchMethodInfo != null) + HarmonyMethodInfo = Harmony.ReversePatch(method, new(ReversePatchMethodInfo), ReversePatchTranspilerMethodInfo); + + if (PrefixMethodInfo != null || PostfixMethodInfo != null || TranspilerMethodInfo != null || FinalizerMethodInfo != null) + { + HarmonyMethodInfo = Harmony.Patch(method, + prefix: PrefixMethodInfo != null ? new(PrefixMethodInfo, PrefixMethodPriority) : null, + postfix: PostfixMethodInfo != null ? new(PostfixMethodInfo, PostfixMethodPriority) : null, + transpiler: TranspilerMethodInfo != null ? new(TranspilerMethodInfo, TranspilerMethodPriority) : null, + finalizer: FinalizerMethodInfo != null ? new(FinalizerMethodInfo, FinalizerMethodPriority) : null); + } + } + catch (Exception e) + { + Log.Error($"{ModName} encountered an exception while trying to patch {method.FullDescription()} with {PrefixMethodInfo.FullDescription()}" + + $", {PostfixMethodInfo.FullDescription()}, {TranspilerMethodInfo.FullDescription()}, {FinalizerMethodInfo.FullDescription()}:\n{e}"); + } + +#if DEBUG + Log.Message($"{ModName} applied {GetType().Name} on {method.FullDescription()}"); +#endif + } + } + return HarmonyMethodInfo; + } + + public virtual void TryUnpatch() + { + ShouldBePatched = false; + if (Patched) + { + Patched = false; + foreach (var method in TargetMethodInfos) + { + if (PrefixMethodInfo != null) + { + try + { + Harmony.Unpatch(method, PrefixMethodInfo); + } + catch (Exception e) + { + Log.Error($"{ModName} encountered an exception when unpatching {PrefixMethodInfo.FullDescription()} from {method.FullDescription()}:\n{e}"); + } + } + if (PostfixMethodInfo != null) + { + try + { + Harmony.Unpatch(method, PostfixMethodInfo); + } + catch (Exception e) + { + Log.Error($"{ModName} encountered an exception when unpatching {PostfixMethodInfo.FullDescription()} from {method.FullDescription()}:\n{e}"); + } + } + if (TranspilerMethodInfo != null) + { + try + { + Harmony.Unpatch(method, TranspilerMethodInfo); + } + catch (Exception e) + { + Log.Error($"{ModName} encountered an exception when unpatching {TranspilerMethodInfo.FullDescription()} from {method.FullDescription()}:\n{e}"); + } + } + if (FinalizerMethodInfo != null) + { + try + { + Harmony.Unpatch(method, FinalizerMethodInfo); + } + catch (Exception e) + { + Log.Error($"{ModName} encountered an exception when unpatching {FinalizerMethodInfo.FullDescription()} from {method.FullDescription()}:\n{e}"); + } + } + } + CleanupMethodInfo?.Invoke(null, null); + } + } + + private static int TryGetPriority(MethodInfo info) => info?.TryGetAttribute()?.info.priority ?? Priority.Normal; + + public static T Get() => TryGet() ?? throw new KeyNotFoundException($"Couldn't find FishPatch or IHasFishPatch class {typeof(T).Name}"); + public static T? TryGet() + { + if (typeof(IHasFishPatch).IsAssignableFrom(typeof(T))) + { + foreach (var patch in AllPatchClasses) + { + if (patch is T patchOfT) + return patchOfT; + } + } + else if (typeof(FishPatch).IsAssignableFrom(typeof(T))) + { + foreach (var patchClass in AllPatchClasses) + { + if (patchClass.Patches.TryGet(typeof(T)) is T patch) + return patch; + } + } + + return default; + } + public static IHasFishPatch[] AllPatchClasses { get; } = Assembly.GetExecutingAssembly().GetTypes() + .Where(t => typeof(IHasFishPatch).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract) + .Select(t => (IHasFishPatch)Activator.CreateInstance(t)).ToArray(); + public void ExposeData() => Scribe_Values.Look(ref _enabled, GetType().Name, DefaultState); +} + +public abstract class FirstPriorityFishPatch : FishPatch +{ + public override int PrefixMethodPriority => Priority.First; + public override int PostfixMethodPriority => Priority.First; + public override int TranspilerMethodPriority => Priority.First; + public override int FinalizerMethodPriority => Priority.First; +} + +public static class FishPatchExtensions +{ + public static void PatchAll(this IEnumerable patches) + { + foreach (var patch in patches) + patch.TryPatch(); + } + public static void UnpatchAll(this IEnumerable patches) + { + foreach (var patch in patches) + patch.TryUnpatch(); + } +} + +public class FishPatchHolder : IExposable, IEnumerable +{ + public Dictionary All => _all; + public T Get() where T : FishPatch => (T)All[typeof(T)]; + public FishPatch Get(Type type) => All[type]; + public T? TryGet() where T : FishPatch => All!.TryGetValue(typeof(T)) as T; + public FishPatch? TryGet(Type type) => All!.TryGetValue(type); + public void Add(FishPatch patch) => All[patch.GetType()] = patch; + public void PatchAll() + { + AddPatchesRecursively(_type); + All.Values.PatchAll(); + } + public void UnpatchAll() => All.Values.UnpatchAll(); + public FishPatch this[Type type] => All[type]; + + public FishPatchHolder(Type type) => _type = type; + + public void ExposeData() => Scribe_Collections.Look(ref _all, "patches", valueLookMode: LookMode.Deep); + + private void AddPatchesRecursively(Type type) + { + if (typeof(FishPatch).IsAssignableFrom(type) && !All.ContainsKey(type)) + { + var dupeClasses = FishPatch.AllPatchClasses.Where(patchClass => patchClass.GetType() != _type && patchClass.Patches.All.ContainsKey(type)); + if (dupeClasses.Any()) + { + foreach (var patchClass in dupeClasses) + { + patchClass.Patches[type].Enabled = false; + patchClass.Patches.All.Remove(type); + Log.Warning($"{FishPatchManager.FISHERY} removed a duplicate patch from {patchClass.GetType().FullName}. This is likely caused by no longer valid mod configs"); + } + } + + All.Add(type, (FishPatch)Activator.CreateInstance(type)); + } + + foreach (var nestedType in type.GetNestedTypes(AccessTools.all)) + AddPatchesRecursively(nestedType); + } + + public IEnumerator GetEnumerator() => All.Values.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => All.Values.GetEnumerator(); + + private Dictionary _all = new(); + private Type _type; +} + +public interface IHasFishPatch +{ + public FishPatchHolder Patches { get; } + public FishPatchHolder? PatchHolder { get; set; } + public bool RequiresLoadedGameForPatching { get; } +} + +public interface IHasDescription +{ + public string? Description { get; } +} + +public abstract class ClassWithFishPatches : IHasFishPatch +{ + public virtual FishPatchHolder Patches => _patchHolder ??= new(GetType()); + public virtual FishPatchHolder? PatchHolder { get => _patchHolder; set => _patchHolder = value; } + public virtual bool RequiresLoadedGameForPatching => false; + private FishPatchHolder? _patchHolder; +}*/ \ No newline at end of file diff --git a/Source/FisheryLib/FishTranspiler.cs b/Source/FisheryLib/FishTranspiler.cs new file mode 100644 index 0000000..9c3e999 --- /dev/null +++ b/Source/FisheryLib/FishTranspiler.cs @@ -0,0 +1,2403 @@ +// Copyright (c) 2022 bradson +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +using System.Globalization; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection.Emit; + +namespace FisheryLib; +public static class FishTranspiler +{ + public struct Container + { + public Container(OpCode opcode, object? operand = null) + { + OpCode = opcode; + Operand = operand; + } + + public Container(CodeInstruction instruction) + { + Guard.IsNotNull(instruction, nameof(instruction)); + + OpCode = instruction.opcode; + Operand = instruction.operand; + } + + public Container(Container container) + { + OpCode = container.OpCode; + Operand = container.Operand; + } + + public override string ToString() + => $"{OpCode} {Operand}"; + + public CodeInstruction ToInstruction() + => new(OpCode, Operand); + + public Container Store() + => OpCode.LoadsArgument() ? ToStoreArgument() + : new( + OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToStoreField() + : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToStoreLocalVariable() + : OpCode.StoresArgument() ? OpCode + : ThrowHelper.ThrowInvalidOperationException($"Cannot determine Store instruction for {OpCode}"), + Operand); + + public Container Load() + => OpCode.StoresArgument() ? ToLoadArgument() + : new( + OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToLoadField() + : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToLoadLocalVariable() + : OpCode.LoadsArgument() ? OpCode + : ThrowHelper.ThrowInvalidOperationException($"Cannot determine Load instruction for {OpCode}"), + Operand); + + private Container ToStoreArgument() + => new(OpCode.ToStoreArgument(), GetIndex()); + + private Container ToLoadArgument() + { + var index = GetIndex(); + return new(GetLoadArgumentOpCode(index), index > 3 ? index : null); + } + + public Container Address() + => new(OpCode.ToAddress(), GetIndex()); + + public CodeInstruction WithLabels(params Label[] labels) + => WithLabels((IEnumerable