Fishery
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ModMetaData>
|
||||||
|
<name>Fishery - Modding Library</name>
|
||||||
|
<packageId>bs.fishery</packageId>
|
||||||
|
<supportedVersions>
|
||||||
|
<li>1.3</li>
|
||||||
|
<li>1.4</li>
|
||||||
|
</supportedVersions>
|
||||||
|
<author>bradson</author>
|
||||||
|
<url>https://github.com/bbradson/fishery</url>
|
||||||
|
<loadBefore>
|
||||||
|
<li>Ludeon.RimWorld</li>
|
||||||
|
<li>me.samboycoding.betterloading</li>
|
||||||
|
<li>zetrith.prepatcher</li>
|
||||||
|
</loadBefore>
|
||||||
|
<loadAfter>
|
||||||
|
<li>brrainz.harmony</li>
|
||||||
|
</loadAfter>
|
||||||
|
<modDependencies>
|
||||||
|
<li>
|
||||||
|
<packageId>brrainz.harmony</packageId>
|
||||||
|
<displayName>Harmony</displayName>
|
||||||
|
<steamWorkshopUrl>steam://url/CommunityFilePage/2009463077</steamWorkshopUrl>
|
||||||
|
<downloadUrl>https://github.com/pardeike/HarmonyRimWorld/releases/latest</downloadUrl>
|
||||||
|
</li>
|
||||||
|
</modDependencies>
|
||||||
|
<description>Additions for Harmony to simplify otherwise complex patch operations</description>
|
||||||
|
</ModMetaData>
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
Copyright (c) 2022 bradson
|
||||||
|
|
||||||
Mozilla Public License Version 2.0
|
Mozilla Public License Version 2.0
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
@@ -357,7 +359,7 @@ Exhibit A - Source Code Form License Notice
|
|||||||
|
|
||||||
This Source Code Form is subject to the terms of the Mozilla Public
|
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
|
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
|
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
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# Fishery
|
# 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.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
||||||
|
<AnalysisLevel>preview-all</AnalysisLevel>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
<Configurations>v1.3;v1.4</Configurations>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(Configuration)' == 'v1.3'">
|
||||||
|
<ItemGroup>
|
||||||
|
<!--PackageReference Include="Krafs.Rimworld.Ref" Version="1.3.*" /-->
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>E:\RimWorld\1.3\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib">
|
||||||
|
<HintPath>E:\RimWorld\1.3\RimWorldWin64_Data\Managed\mscorlib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>E:\RimWorld\1.3\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>E:\RimWorld\1.3\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="1Fishery">
|
||||||
|
<HintPath>..\..\1.3\Assemblies\1Fishery.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
<When Condition="'$(Configuration)' == 'v1.4'">
|
||||||
|
<ItemGroup>
|
||||||
|
<!--PackageReference Include="Krafs.Rimworld.Ref" Version="1.4.*-*" /-->
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>E:\RimWorld\1.4\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib">
|
||||||
|
<HintPath>E:\RimWorld\1.4\RimWorldWin64_Data\Managed\mscorlib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.CoreModule">
|
||||||
|
<HintPath>E:\RimWorld\1.4\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.IMGUIModule">
|
||||||
|
<HintPath>E:\RimWorld\1.4\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="1Fishery">
|
||||||
|
<HintPath>..\..\1.4\Assemblies\1Fishery.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.*" />
|
||||||
|
<PackageReference Include="xunit" Version="2.*" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.*">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.*">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
global using System;
|
||||||
|
global using Xunit;
|
||||||
|
|
||||||
|
namespace FisheryLib.Tests;
|
||||||
|
|
||||||
|
public class UnitTest1
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helpers for working with the <see cref="bool"/> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class BoolExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="bool"/> value into a <see cref="byte"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The input value to convert.</param>
|
||||||
|
/// <returns>1 if <paramref name="flag"/> is <see langword="true"/>, 0 otherwise.</returns>
|
||||||
|
/// <remarks>This method does not contain branching instructions.</remarks>
|
||||||
|
[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*)©
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="bool"/> value to an <see cref="int"/> mask with
|
||||||
|
/// all bits representing the value of the input flag (either 0xFFFFFFFF or 0x00000000).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The input value to convert.</param>
|
||||||
|
/// <returns>0xFFFFFFFF if <paramref name="flag"/> is <see langword="true"/>, 0x00000000 otherwise.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method does not contain branching instructions, and it is only guaranteed to work with
|
||||||
|
/// <see cref="bool"/> values being either 0 or 1. Operations producing a <see cref="bool"/> result,
|
||||||
|
/// such as numerical comparisons, always result in a valid value. If the <see cref="bool"/> value is
|
||||||
|
/// produced by fields with a custom <see cref="System.Runtime.InteropServices.FieldOffsetAttribute"/>,
|
||||||
|
/// or by using <see cref="Unsafe.As{T}"/> 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.
|
||||||
|
/// </remarks>
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="bool"/> value to a <see cref="long"/> mask with
|
||||||
|
/// all bits representing the value of the input flag (either all 1s or 0s).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flag">The input value to convert.</param>
|
||||||
|
/// <returns>All 1s if <paramref name="flag"/> is <see langword="true"/>, all 0s otherwise.</returns>
|
||||||
|
/// <remarks>This method does not contain branching instructions. See additional note in <see cref="ToBitwiseMask32"/>.</remarks>
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<T>(this List<T> list, int index, [NotNullWhen(true)] out T? item)
|
||||||
|
{
|
||||||
|
if (list.Count > index)
|
||||||
|
{
|
||||||
|
item = list[index]!;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Taken from Span<>.this[] and slower than List<>.this[] due to the ArrayAdjustment
|
||||||
|
/// </summary>
|
||||||
|
internal static T GetItemUnchecked<T>(this List<T> list, int index)
|
||||||
|
=> Unsafe.Add(ref Unsafe.AddByteOffset(ref Unsafe.As<Pinnable<T>>(list._items).Data, PerTypeValues<T>.ArrayAdjustment), index)!;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private sealed class Pinnable<T>
|
||||||
|
{
|
||||||
|
public T? Data;
|
||||||
|
}
|
||||||
|
private static class PerTypeValues<T>
|
||||||
|
{
|
||||||
|
public static readonly IntPtr ArrayAdjustment = MeasureArrayAdjustment();
|
||||||
|
private static IntPtr MeasureArrayAdjustment()
|
||||||
|
{
|
||||||
|
var array = new T[1];
|
||||||
|
return Unsafe.ByteOffset(ref Unsafe.As<Pinnable<T>>(array).Data!, ref array[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetItem<T>(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<T>(this IEnumerable<T> enumerable, int length)
|
||||||
|
{
|
||||||
|
var array = new T[length];
|
||||||
|
|
||||||
|
if (enumerable is IList<T> ilist)
|
||||||
|
array.Fill(ilist);
|
||||||
|
else
|
||||||
|
array.FillUsingEnumerable(enumerable);
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Telement[] ToArray<Tenumerable, Telement>(this Tenumerable enumerable, Telement[] destination)
|
||||||
|
where Tenumerable : IList<Telement>
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(destination);
|
||||||
|
|
||||||
|
destination.Fill(enumerable);
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T[] ToArray<T>(this IEnumerable<T> enumerable, T[] destination)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(destination);
|
||||||
|
|
||||||
|
if (enumerable is IList<T> ilist)
|
||||||
|
destination.Fill(ilist);
|
||||||
|
else
|
||||||
|
destination.FillUsingEnumerable(enumerable);
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillUsingEnumerable<T>(this T[] array, IEnumerable<T> 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<Telement, Tcollection>(this Telement[] array, Tcollection collection, int startIndex = 0, int count = -1)
|
||||||
|
where Tcollection : IList<Telement>
|
||||||
|
{
|
||||||
|
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<T>(this T[] array, IEnumerable<T> enumerable, int startIndex = 0, int count = -1)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(enumerable);
|
||||||
|
|
||||||
|
if (enumerable is IList<T> ilist)
|
||||||
|
array.Fill(ilist, startIndex, count);
|
||||||
|
else
|
||||||
|
array.FillUsingEnumerable(enumerable, startIndex, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ref TValue GetReference<TKey, TValue>(this Dictionary<TKey, TValue> 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<TKey>(key))
|
||||||
|
return ref entry.value;
|
||||||
|
|
||||||
|
bucket = entry.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ref ThrowKeyNotFoundException<TKey, TValue>(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key</param>
|
||||||
|
/// <returns>ref TValue or Unsafe.NullRef{TValue}</returns>
|
||||||
|
public static ref TValue TryGetReferenceUnsafe<TKey, TValue>(this Dictionary<TKey, TValue> 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<TKey>(key))
|
||||||
|
return ref entry.value;
|
||||||
|
|
||||||
|
bucket = entry.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ref Unsafe.NullRef<TValue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ref TValue TryGetReferenceUnsafe<TKey, TValue>(this Dictionary<TKey, TValue> 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<TValue>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TValue? TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> 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<TKey, TValue>(this Dictionary<TKey, TValue> 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<TKey>(key))
|
||||||
|
return entry.value;
|
||||||
|
|
||||||
|
bucket = entry.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
private static ref V ThrowKeyNotFoundException<T, V>(T key)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(key);
|
||||||
|
ThrowKeyNotFoundException(key);
|
||||||
|
return ref Unsafe.NullRef<V>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[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<T>(this List<T> list) => ref list._version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T[] ItemsUnchecked<T>(this List<T> list) => list._items;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a span pointing to a list's internal _items array. Keep in mind list.Version() needs to change every time items are modified.
|
||||||
|
/// </summary>
|
||||||
|
public static Span<T> AsSpanUnchecked<T>(this List<T> list) => new(list._items, 0, list.Count);
|
||||||
|
|
||||||
|
public static ReadOnlySpan<T> AsReadOnlySpan<T>(this List<T> list) => new(list._items, 0, list.Count);
|
||||||
|
|
||||||
|
public static void ReplaceContentsWith<T, V>(this List<T> list, V collection) where V : ICollection<T>
|
||||||
|
{
|
||||||
|
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<T>(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<Type, GenericBase> ListExtensionCache => _listExtensionCache ??= new();
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static Dictionary<Type, GenericBase>? _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<T> : GenericBase
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override void AddRange(IList list, ICollection collection) => ((List<T>)list).AddRange((IEnumerable<T>)collection);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override Array ToArray(IList list) => ((List<T>)list).ToArray();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override IList New(IEnumerable enumerable) => new List<T>((IEnumerable<T>)enumerable);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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, TTo>(TFrom from) where TFrom : IConvertible
|
||||||
|
=> FunctionPointers.Convert<TFrom>.To<TTo>.Default(from, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe TTo To<TFrom, TTo>(TFrom from, IFormatProvider provider) where TFrom : IConvertible
|
||||||
|
=> FunctionPointers.Convert<TFrom>.To<TTo>.Default(from, provider);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An attribute that allows parameters to receive the expression of other parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Internal copy from the BCL attribute.</remarks>
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
|
||||||
|
internal sealed class CallerArgumentExpressionAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CallerArgumentExpressionAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameterName">The condition parameter value.</param>
|
||||||
|
public CallerArgumentExpressionAttribute(string parameterName) => ParameterName = parameterName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parameter name the expression is retrieved from.
|
||||||
|
/// </summary>
|
||||||
|
public string ParameterName { get; }
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helpers for working with types.
|
||||||
|
/// </summary>
|
||||||
|
public static class TypeExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The mapping of built-in types to their simple representation.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly IReadOnlyDictionary<Type, string> BuiltInTypesMap = new Dictionary<Type, string>
|
||||||
|
{
|
||||||
|
[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"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A thread-safe mapping of precomputed string representation of types.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly ConditionalWeakTable<Type, string> DisplayNames = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a simple string representation of a type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The input type.</param>
|
||||||
|
/// <returns>The string representation of <paramref name="type"/>.</returns>
|
||||||
|
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<Type> 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<T> types are displayed as T?
|
||||||
|
if (genericTypeDefinition == typeof(Nullable<>))
|
||||||
|
{
|
||||||
|
var nullableArguments = type.GetGenericArguments();
|
||||||
|
|
||||||
|
return $"{FormatDisplayString(nullableArguments[0], 0, nullableArguments)}?";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueTuple<T1, T2> 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<T>
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helpers for working with value types.
|
||||||
|
/// </summary>
|
||||||
|
public static class ValueTypeExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the table of hex characters (doesn't allocate, maps to .text section, see <see href="https://github.com/dotnet/roslyn/pull/24621"/>).
|
||||||
|
/// </summary>
|
||||||
|
private static ReadOnlySpan<byte> 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'
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hexadecimal <see cref="string"/> representation of a given <typeparamref name="T"/> value, left-padded and ordered as big-endian.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The input type to format to <see cref="string"/>.</typeparam>
|
||||||
|
/// <param name="value">The input value to format to <see cref="string"/>.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The hexadecimal representation of <paramref name="value"/> (with the '0x' prefix), left-padded to byte boundaries and ordered as big-endian.
|
||||||
|
/// </returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// As a byte (8 bits) is represented by two hexadecimal digits (each representing a group of 4 bytes), each <see cref="string"/>
|
||||||
|
/// representation will always contain an even number of digits. For instance:
|
||||||
|
/// <code>
|
||||||
|
/// Console.WriteLine(1.ToHexString()); // "0x01"
|
||||||
|
/// Console.WriteLine(((byte)255).ToHexString()); // "0xFF"
|
||||||
|
/// Console.WriteLine((-1).ToHexString()); // "0xFFFFFFFF"
|
||||||
|
/// </code>
|
||||||
|
/// </remarks>
|
||||||
|
public static unsafe string ToHexString<T>(this T value)
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
var sizeOfT = Unsafe.SizeOf<T>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class Guard
|
||||||
|
{
|
||||||
|
<#
|
||||||
|
GenerateTextForItems(EnumerableTypes, item =>
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must be empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is != 0.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsEmpty<T>(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "")
|
||||||
|
{
|
||||||
|
if (<#=item.Name#>.<#=item.Size#> == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsEmpty(<#=item.Cast#><#=item.Name#>, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must not be empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is == 0.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotEmpty<T>(<#=item.Type#> <#=item.Name#>, [CallerArgumentExpression("<#=item.Name#>")] string name = "")
|
||||||
|
{
|
||||||
|
if (<#=item.Name#>.<#=item.Size#> != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
<#
|
||||||
|
if (item.Type == "Span<T>")
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithSpan<T>(name);
|
||||||
|
<#
|
||||||
|
}
|
||||||
|
else if (item.Type == "ReadOnlySpan<T>")
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan<T>(name);
|
||||||
|
<#
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEmpty<<#=item.Type#>>(name);
|
||||||
|
<#
|
||||||
|
}
|
||||||
|
#>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size of a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is != <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size not equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is == <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeNotEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size over a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is <= <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeGreaterThan<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size of at least or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is < <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeGreaterThanOrEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size of less than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is >= <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeLessThan<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <#=item.XmlType#> instance must have a size of less than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="<#=item.Name#>"/> is > <paramref name="size"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeLessThanOrEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the source <#=item.XmlType#> instance must have the same size of a destination <#=item.XmlType#> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="source">The source <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="destination">The destination <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="source"/> is != the one of <paramref name="destination"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeEqualTo<T>(<#=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);
|
||||||
|
<#
|
||||||
|
}
|
||||||
|
#>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the source <#=item.XmlType#> instance must have a size of less than or equal to that of a destination <#=item.XmlType#> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="source">The source <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="destination">The destination <#=item.XmlType#> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="source"/> is > the one of <paramref name="destination"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void HasSizeLessThanOrEqualTo<T>(<#=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);
|
||||||
|
<#
|
||||||
|
}
|
||||||
|
#>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input index is valid for a given <#=item.XmlType#> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="index">The input index to be used to access <paramref name="<#=item.Name#>"/>.</param>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to use to validate <paramref name="index"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="index"/> is not valid to access <paramref name="<#=item.Name#>"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsInRangeFor<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input index is not valid for a given <#=item.XmlType#> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <#=item.XmlType#> instance.</typeparam>
|
||||||
|
/// <param name="index">The input index to be used to access <paramref name="<#=item.Name#>"/>.</param>
|
||||||
|
/// <param name="<#=item.Name#>">The input <#=item.XmlType#> instance to use to validate <paramref name="index"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="index"/> is valid to access <paramref name="<#=item.Name#>"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotInRangeFor<T>(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);
|
||||||
|
}
|
||||||
|
<#
|
||||||
|
});
|
||||||
|
#>
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class Guard
|
||||||
|
{
|
||||||
|
<#
|
||||||
|
GenerateTextForItems(NumericTypes, typeInfo =>
|
||||||
|
{
|
||||||
|
var (type, prefix) = typeInfo;
|
||||||
|
#>
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see <#=prefix#>="<#=type#>"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is != <paramref name="target"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value == target)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be not equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see <#=prefix#>="<#=type#>"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is == <paramref name="target"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotEqualTo(<#=type#> value, <#=type#> target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value != target)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be less than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsLessThan(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value < maximum)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be less than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsLessThanOrEqualTo(<#=type#> value, <#=type#> maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value <= maximum)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be greater than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is <= <paramref name="minimum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsGreaterThan(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value > minimum)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be greater than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsGreaterThanOrEqualTo(<#=type#> value, <#=type#> minimum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value >= minimum)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or < <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is <= <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="minimum"/> or < <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/> or > <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see <#=prefix#>="<#=type#>"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <see <#=prefix#>="<#=type#>"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or <= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
<#
|
||||||
|
});
|
||||||
|
#>
|
||||||
|
}
|
||||||
@@ -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<T>` as type constraint.
|
||||||
|
- In some cases, using generic methods just isn't possible. For instance, types like `Span<T>` and `ReadOnlySpan<T>` 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.
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(Span<T> span, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Span<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Span<T> source, Span<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Span<T> source, Span<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, Span<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, Span<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(ReadOnlySpan<T> span, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must be empty, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlySpan<T> span, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(span.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlySpan<T> source, Span<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlySpan<T> source, Span<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ReadOnlySpan<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ReadOnlySpan<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(Memory<T> memory, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Memory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(Memory<T> source, Memory<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(Memory<T> source, Memory<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(Memory<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, Memory<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, Memory<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(ReadOnlyMemory<T> memory, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must be empty, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlyMemory<T> memory, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(memory.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ReadOnlyMemory<T> source, Memory<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ReadOnlyMemory<T> source, Memory<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ReadOnlyMemory<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Length)} (the destination), had a size of {AssertString(source.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ReadOnlyMemory<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ReadOnlyMemory<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(T[] array, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T[]).ToTypeString()}) must be empty, had a size of {AssertString(array.Length)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(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)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(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)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(List<T> list, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must be empty, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(List<T> list, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(list.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(List<T> source, List<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(List<T> source, List<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(List<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, List<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, List<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(ICollection<T> collection, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ICollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(ICollection<T> source, ICollection<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(ICollection<T> source, ICollection<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(ICollection<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, ICollection<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, ICollection<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(IReadOnlyCollection<T> collection, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must be empty, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size not equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size over {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size of at least {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(IReadOnlyCollection<T> collection, int size, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than or equal to {size}, had a size of {AssertString(collection.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(IReadOnlyCollection<T> source, ICollection<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(IReadOnlyCollection<T> source, ICollection<T> destination, string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The source {AssertString(name)} ({typeof(IReadOnlyCollection<T>).ToTypeString()}) must have a size less than or equal to {AssertString(destination.Count)} (the destination), had a size of {AssertString(source.Count)}.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(int index, IReadOnlyCollection<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(int index, IReadOnlyCollection<T> 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<T>).ToTypeString()}), was {AssertString(index)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
partial class ThrowHelper
|
||||||
|
{
|
||||||
|
<#
|
||||||
|
GenerateTextForItems(EnumerableTypes, item =>
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.IsEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeNotEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeNotEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThan<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeGreaterThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeGreaterThanOrEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThan{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThan<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],int,string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="Guard.HasSizeLessThanOrEqualTo{T}(T[],T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForHasSizeLessThanOrEqualTo<T>(<#=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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRangeFor<T>(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)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="Guard.IsNotInRangeFor{T}(int,T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRangeFor<T>(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)}.");
|
||||||
|
}
|
||||||
|
<#
|
||||||
|
});
|
||||||
|
#>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<#@ template language="C#"#>
|
||||||
|
<#@ assembly name="System.Core" #>
|
||||||
|
<#@ import namespace="System.Collections.Generic" #>
|
||||||
|
<#@ output extension=".g.cs"#>
|
||||||
|
// =====================
|
||||||
|
// Auto generated file
|
||||||
|
// =====================
|
||||||
|
<#+
|
||||||
|
/// <summary>
|
||||||
|
/// A model representing the info on an enumerable type
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the current type
|
||||||
|
/// </summary>
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the XML-formatted name of the current type (eg. with {T} instead of <T>)
|
||||||
|
/// </summary>
|
||||||
|
public string XmlType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the variable name to use
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the property to use to retrieve the length of the current type
|
||||||
|
/// </summary>
|
||||||
|
public string Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether or not the current type has a "Count" property
|
||||||
|
/// </summary>
|
||||||
|
public bool HasCountProperty => Size == "Count";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the destination type, when comparing counts across different collections
|
||||||
|
/// </summary>
|
||||||
|
public string DestinationType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the (optional) casting to resolve the diamond problem between different interfaces
|
||||||
|
/// </summary>
|
||||||
|
public string Cast { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of available enumerable types to generate APIs for
|
||||||
|
/// </summary>
|
||||||
|
static readonly IReadOnlyList<EnumerableTypeInfo> EnumerableTypes = new[]
|
||||||
|
{
|
||||||
|
new EnumerableTypeInfo("Span<T>", "<see cref=\"Span{T}\"/>", "span", "Length", "Span<T>", ""),
|
||||||
|
new EnumerableTypeInfo("ReadOnlySpan<T>", "<see cref=\"ReadOnlySpan{T}\"/>", "span", "Length", "Span<T>", ""),
|
||||||
|
new EnumerableTypeInfo("Memory<T>", "<see cref=\"Memory{T}\"/>", "memory", "Length", "Memory<T>", ""),
|
||||||
|
new EnumerableTypeInfo("ReadOnlyMemory<T>", "<see cref=\"ReadOnlyMemory{T}\"/>", "memory", "Length", "Memory<T>", ""),
|
||||||
|
new EnumerableTypeInfo("T[]", "<see typeparamref=\"T\"/> array", "array", "Length", "T[]", ""),
|
||||||
|
new EnumerableTypeInfo("List<T>", "<see cref=\"List{T}\"/>", "list", "Count", "List<T>", "(ICollection<T>)"),
|
||||||
|
new EnumerableTypeInfo("ICollection<T>", "<see cref=\"ICollection{T}\"/>", "collection", "Count", "ICollection<T>", ""),
|
||||||
|
new EnumerableTypeInfo("IReadOnlyCollection<T>", "<see cref=\"IReadOnlyCollection{T}\"/>", "collection", "Count", "ICollection<T>", ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of available numeric types to generate APIs for
|
||||||
|
/// </summary>
|
||||||
|
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")
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates text for a given sequence of items, automatically adding the necessary spacing
|
||||||
|
/// </summary>
|
||||||
|
void GenerateTextForItems<T>(IReadOnlyList<T> items, Action<T> 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#>
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public static partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="true"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="false"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsTrue([DoesNotReturnIf(false)] bool value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsTrue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="true"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <param name="message">A message to display if <paramref name="value"/> is <see langword="false"/>.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="false"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsTrue([DoesNotReturnIf(false)] bool value, string name, string message)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsTrue(name, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="false"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="true"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsFalse([DoesNotReturnIf(true)] bool value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsFalse(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="false"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <param name="message">A message to display if <paramref name="value"/> is <see langword="true"/>.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="true"/>.</exception>
|
||||||
|
[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
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="true"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <param name="message">A message to display if <paramref name="value"/> is <see langword="false"/>.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="false"/>.</exception>
|
||||||
|
[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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be <see langword="false"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="bool"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <param name="message">A message to display if <paramref name="value"/> is <see langword="true"/>.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="true"/>.</exception>
|
||||||
|
[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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interpolated string handler for <see cref="IsTrue(bool, string, ref IsTrueInterpolatedStringHandler)"/> that only performs formatting if the assert fails.
|
||||||
|
/// </summary>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
[InterpolatedStringHandler]
|
||||||
|
public struct IsTrueInterpolatedStringHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The handler used to perform the formatting.
|
||||||
|
/// </summary>
|
||||||
|
private StringBuilder.AppendInterpolatedStringHandler handler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The underlying <see cref="StringBuilder"/> instance used by <see cref="handler"/>, if any.
|
||||||
|
/// </summary>
|
||||||
|
private StringBuilder? builder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of the handler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="literalLength">The number of constant characters outside of interpolation expressions in the interpolated string.</param>
|
||||||
|
/// <param name="formattedCount">The number of interpolation expressions in the interpolated string.</param>
|
||||||
|
/// <param name="condition">The condition passed to the <see cref="Guard"/> method.</param>
|
||||||
|
/// <param name="shouldAppend">A value indicating whether formatting should proceed.</param>
|
||||||
|
/// <remarks>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.</remarks>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts the built string from the handler.
|
||||||
|
/// </summary>
|
||||||
|
internal string ToStringAndClear()
|
||||||
|
{
|
||||||
|
string message = this.builder?.ToString() ?? string.Empty;
|
||||||
|
|
||||||
|
this = default;
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendLiteral(string)"/>
|
||||||
|
public void AppendLiteral(string value)
|
||||||
|
{
|
||||||
|
this.handler.AppendLiteral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
||||||
|
public void AppendFormatted<T>(T value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
||||||
|
public void AppendFormatted<T>(T value, string? format)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
||||||
|
public void AppendFormatted<T>(T value, int alignment)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
||||||
|
public void AppendFormatted<T>(T value, int alignment, string? format)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char})"/>
|
||||||
|
public void AppendFormatted(ReadOnlySpan<char> value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char}, int, string?)"/>
|
||||||
|
public void AppendFormatted(ReadOnlySpan<char> value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?)"/>
|
||||||
|
public void AppendFormatted(string? value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?, int, string?)"/>
|
||||||
|
public void AppendFormatted(string? value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
||||||
|
public void AppendFormatted(object? value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an interpolated string handler for <see cref="IsFalse(bool, string, ref IsFalseInterpolatedStringHandler)"/> that only performs formatting if the assert fails.
|
||||||
|
/// </summary>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
[InterpolatedStringHandler]
|
||||||
|
public struct IsFalseInterpolatedStringHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The handler used to perform the formatting.
|
||||||
|
/// </summary>
|
||||||
|
private StringBuilder.AppendInterpolatedStringHandler handler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The underlying <see cref="StringBuilder"/> instance used by <see cref="handler"/>, if any.
|
||||||
|
/// </summary>
|
||||||
|
private StringBuilder? builder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of the handler.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="literalLength">The number of constant characters outside of interpolation expressions in the interpolated string.</param>
|
||||||
|
/// <param name="formattedCount">The number of interpolation expressions in the interpolated string.</param>
|
||||||
|
/// <param name="condition">The condition passed to the <see cref="Guard"/> method.</param>
|
||||||
|
/// <param name="shouldAppend">A value indicating whether formatting should proceed.</param>
|
||||||
|
/// <remarks>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.</remarks>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts the built string from the handler.
|
||||||
|
/// </summary>
|
||||||
|
internal string ToStringAndClear()
|
||||||
|
{
|
||||||
|
string message = this.builder?.ToString() ?? string.Empty;
|
||||||
|
|
||||||
|
this = default;
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendLiteral(string)"/>
|
||||||
|
public void AppendLiteral(string value)
|
||||||
|
{
|
||||||
|
this.handler.AppendLiteral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T)"/>
|
||||||
|
public void AppendFormatted<T>(T value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/>
|
||||||
|
public void AppendFormatted<T>(T value, string? format)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int)"/>
|
||||||
|
public void AppendFormatted<T>(T value, int alignment)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/>
|
||||||
|
public void AppendFormatted<T>(T value, int alignment, string? format)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char})"/>
|
||||||
|
public void AppendFormatted(ReadOnlySpan<char> value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char}, int, string?)"/>
|
||||||
|
public void AppendFormatted(ReadOnlySpan<char> value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?)"/>
|
||||||
|
public void AppendFormatted(string? value)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?, int, string?)"/>
|
||||||
|
public void AppendFormatted(string? value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/>
|
||||||
|
public void AppendFormatted(object? value, int alignment = 0, string? format = null)
|
||||||
|
{
|
||||||
|
this.handler.AppendFormatted(value, alignment, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is <see langword="default"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not <see langword="default"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsDefault<T>(T value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : struct, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (value.Equals(default))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsDefault(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is not <see langword="default"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is <see langword="default"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotDefault<T>(T value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : struct, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (!value.Equals(default))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotDefault<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is != <paramref name="target"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsEqualTo<T>(T value, T target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (value.Equals(target))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be not equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is == <paramref name="target"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotEqualTo<T>(T value, T target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IEquatable<T>
|
||||||
|
{
|
||||||
|
if (!value.Equals(target))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be a bitwise match with a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not a bitwise match for <paramref name="target"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe void IsBitwiseEqualTo<T>(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<T, byte>(ref value);
|
||||||
|
var targetByte = Unsafe.As<T, byte>(ref target);
|
||||||
|
|
||||||
|
if (valueByte == targetByte)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
else if (sizeof(T) == 2)
|
||||||
|
{
|
||||||
|
var valueUShort = Unsafe.As<T, ushort>(ref value);
|
||||||
|
var targetUShort = Unsafe.As<T, ushort>(ref target);
|
||||||
|
|
||||||
|
if (valueUShort == targetUShort)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
else if (sizeof(T) == 4)
|
||||||
|
{
|
||||||
|
var valueUInt = Unsafe.As<T, uint>(ref value);
|
||||||
|
var targetUInt = Unsafe.As<T, uint>(ref target);
|
||||||
|
|
||||||
|
if (valueUInt == targetUInt)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
else if (sizeof(T) == 8)
|
||||||
|
{
|
||||||
|
var valueULong = Unsafe.As<T, ulong>(ref value);
|
||||||
|
var targetULong = Unsafe.As<T, ulong>(ref target);
|
||||||
|
|
||||||
|
if (Bit64Compare(ref valueULong, ref targetULong))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
else if (sizeof(T) == 16)
|
||||||
|
{
|
||||||
|
var valueULong0 = Unsafe.As<T, ulong>(ref value);
|
||||||
|
var targetULong0 = Unsafe.As<T, ulong>(ref target);
|
||||||
|
|
||||||
|
if (Bit64Compare(ref valueULong0, ref targetULong0))
|
||||||
|
{
|
||||||
|
var valueULong1 = Unsafe.Add(ref Unsafe.As<T, ulong>(ref value), 1);
|
||||||
|
var targetULong1 = Unsafe.Add(ref Unsafe.As<T, ulong>(ref target), 1);
|
||||||
|
|
||||||
|
if (Bit64Compare(ref valueULong1, ref targetULong1))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForBitwiseEqualTo(value, target, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Span<byte> valueBytes = new(Unsafe.AsPointer(ref value), sizeof(T));
|
||||||
|
Span<byte> 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<ulong, int>(ref left);
|
||||||
|
ref var r1 = ref Unsafe.As<ulong, int>(ref right);
|
||||||
|
|
||||||
|
return r0 == r1 &&
|
||||||
|
Unsafe.Add(ref r0, 1) == Unsafe.Add(ref r1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return left == right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be less than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsLessThan<T>(T value, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(maximum) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThan(value, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be less than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsLessThanOrEqualTo<T>(T value, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(maximum) <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo(value, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be greater than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is <= <paramref name="minimum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsGreaterThan<T>(T value, T minimum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThan(value, minimum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be greater than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to avoid boxing the parameters, if they are value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsGreaterThanOrEqualTo<T>(T value, T minimum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) >= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo(value, minimum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsInRange<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsInRange(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given range.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or < <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotInRange<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) >= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotInRange(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is <= <paramref name="minimum"/> or >= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsBetween<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) > 0 && value.CompareTo(maximum) < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetween(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The exclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The exclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is > <paramref name="minimum"/> or < <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in (<paramref name="minimum"/>, <paramref name="maximum"/>)", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotBetween<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) <= 0 || value.CompareTo(maximum) >= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetween(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is < <paramref name="minimum"/> or > <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsBetweenOrEqualTo<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) >= 0 && value.CompareTo(maximum) <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be in a given interval.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="minimum">The inclusive minimum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="maximum">The inclusive maximum <typeparamref name="T"/> value that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="value"/> is >= <paramref name="minimum"/> or <= <paramref name="maximum"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This API asserts the equivalent of "<paramref name="value"/> not in [<paramref name="minimum"/>, <paramref name="maximum"/>]", using arithmetic notation.
|
||||||
|
/// The method is generic to avoid boxing the parameters, if they are value types.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotBetweenOrEqualTo<T>(T value, T minimum, T maximum, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : notnull, IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(minimum) < 0 || value.CompareTo(maximum) > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo(value, minimum, maximum, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="int"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="int"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="int"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="int"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) <= <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="long"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="long"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="long"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="long"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) <= <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="float"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="float"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="float"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="float"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) <= <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="double"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="double"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="double"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see cref="double"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) <= <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see langword="nint"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) > <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be within a given distance from a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see langword="nint"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <see langword="nint"/> value to test for.</param>
|
||||||
|
/// <param name="delta">The maximum distance to allow between <paramref name="value"/> and <paramref name="target"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if (<paramref name="value"/> - <paramref name="target"/>) <= <paramref name="delta"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Stream"/> instance must support reading.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The input <see cref="Stream"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="stream"/> doesn't support reading.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void CanRead(Stream stream, [CallerArgumentExpression("stream")] string name = "")
|
||||||
|
{
|
||||||
|
if (stream.CanRead)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForCanRead(stream, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Stream"/> instance must support writing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The input <see cref="Stream"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="stream"/> doesn't support writing.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void CanWrite(Stream stream, [CallerArgumentExpression("stream")] string name = "")
|
||||||
|
{
|
||||||
|
if (stream.CanWrite)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForCanWrite(stream, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Stream"/> instance must support seeking.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The input <see cref="Stream"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="stream"/> doesn't support seeking.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void CanSeek(Stream stream, [CallerArgumentExpression("stream")] string name = "")
|
||||||
|
{
|
||||||
|
if (stream.CanSeek)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForCanSeek(stream, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Stream"/> instance must be at the starting position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The input <see cref="Stream"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="stream"/> is not at the starting position.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsAtStartPosition(Stream stream, [CallerArgumentExpression("stream")] string name = "")
|
||||||
|
{
|
||||||
|
if (stream.Position == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsAtStartPosition(stream, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must be <see langword="null"/> or empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is neither <see langword="null"/> nor empty.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNullOrEmpty(string? text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNullOrEmpty(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must not be <see langword="null"/> or empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown if <paramref name="text"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is empty.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotNullOrEmpty([NotNull] string? text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotNullOrEmpty(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must be <see langword="null"/> or whitespace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is neither <see langword="null"/> nor whitespace.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNullOrWhiteSpace(string? text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNullOrWhiteSpace(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must not be <see langword="null"/> or whitespace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown if <paramref name="text"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is whitespace.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotNullOrWhiteSpace([NotNull] string? text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotNullOrWhiteSpace(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must be empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is empty.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsEmpty(string text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (text.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsEmpty(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must not be empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is empty.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotEmpty(string text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (text.Length != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotEmpty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must be whitespace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is neither <see langword="null"/> nor whitespace.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsWhiteSpace(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must not be <see langword="null"/> or whitespace.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="text"/> is <see langword="null"/> or whitespace.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotWhiteSpace(string text, [CallerArgumentExpression("text")] string name = "")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(text))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotWhiteSpace(text, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size of a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is != <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size not equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is == <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size over a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is <= <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size of at least specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is < <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size of less than a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is >= <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="string"/> instance must have a size of less than or equal to a specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="size">The target size to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is > <paramref name="size"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the source <see cref="string"/> instance must have the same size of a destination <see cref="string"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The source <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="destination">The destination <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is != the one of <paramref name="destination"/>.</exception>
|
||||||
|
/// <remarks>The <see cref="string"/> type is immutable, but the name of this API is kept for consistency with the other overloads.</remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the source <see cref="string"/> instance must have a size of less than or equal to that of a destination <see cref="string"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The source <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="destination">The destination <see cref="string"/> instance to check the size for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the size of <paramref name="text"/> is > the one of <paramref name="destination"/>.</exception>
|
||||||
|
/// <remarks>The <see cref="string"/> type is immutable, but the name of this API is kept for consistency with the other overloads.</remarks>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input index is valid for a given <see cref="string"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The input index to be used to access <paramref name="text"/>.</param>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to use to validate <paramref name="index"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="index"/> is not valid to access <paramref name="text"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input index is not valid for a given <see cref="string"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The input index to be used to access <paramref name="text"/>.</param>
|
||||||
|
/// <param name="text">The input <see cref="string"/> instance to use to validate <paramref name="index"/>.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="index"/> is valid to access <paramref name="text"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is in a completed state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is not in a completed state.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsCompleted(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (task.IsCompleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsCompleted(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is not in a completed state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is in a completed state.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotCompleted(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (!task.IsCompleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotCompleted(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance has been completed successfully.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> has not been completed successfully.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (task.Status == TaskStatus.RanToCompletion)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsCompletedSuccessfully(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance has not been completed successfully.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> has been completed successfully.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotCompletedSuccessfully(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (task.Status != TaskStatus.RanToCompletion)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotCompletedSuccessfully(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is faulted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is not faulted.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsFaulted(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (task.IsFaulted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsFaulted(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is not faulted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is faulted.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotFaulted(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (!task.IsFaulted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotFaulted(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is canceled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is not canceled.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsCanceled(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (task.IsCanceled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsCanceled(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance is not canceled.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> is canceled.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotCanceled(Task task, [CallerArgumentExpression("task")] string name = "")
|
||||||
|
{
|
||||||
|
if (!task.IsCanceled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotCanceled(task, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance has a specific status.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="status">The task status that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> doesn't match <paramref name="status"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input <see cref="Task"/> instance has not a specific status.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task">The input <see cref="Task"/> instance to test.</param>
|
||||||
|
/// <param name="status">The task status that is accepted.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="task"/> matches <paramref name="status"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper methods to verify conditions when running code.
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerStepThrough]
|
||||||
|
public static partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of reference value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not <see langword="null"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNull<T>(T? value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNull(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of nullable value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not <see langword="null"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNull<T>(T? value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNull(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is not <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of reference value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is <see langword="null"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotNull<T>([NotNull] T? value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value is not null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentNullExceptionForIsNotNull<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is not <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of nullable value type being tested.</typeparam>
|
||||||
|
/// <param name="value">The input value to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is <see langword="null"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotNull<T>([NotNull] T? value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (value is not null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentNullExceptionForIsNotNull<T?>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is of a specific type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not of type <typeparamref name="T"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsOfType<T>(object value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value.GetType() == typeof(T))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsOfType<T>(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is not of a specific type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is of type <typeparamref name="T"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotOfType<T>(object value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value.GetType() != typeof(T))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotOfType<T>(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is of a specific type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="type">The type to look for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the type of <paramref name="value"/> is not the same as <paramref name="type"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value is not of a specific type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="type">The type to look for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if the type of <paramref name="value"/> is the same as <paramref name="type"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value can be assigned to a specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type to check the input value against.</typeparam>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> can't be assigned to type <typeparamref name="T"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsAssignableToType<T>(object value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value is T)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsAssignableToType<T>(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value can't be assigned to a specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type to check the input value against.</typeparam>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> can be assigned to type <typeparamref name="T"/>.</exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsNotAssignableToType<T>(object value, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
{
|
||||||
|
if (value is not T)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsNotAssignableToType<T>(value, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value can be assigned to a specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="type">The type to look for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> can't be assigned to <paramref name="type"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value can't be assigned to a specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The input <see cref="object"/> to test.</param>
|
||||||
|
/// <param name="type">The type to look for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> can be assigned to <paramref name="type"/>.</exception>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must be the same instance as the target value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is not the same instance as <paramref name="target"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to prevent using it with value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsReferenceEqualTo<T>(T value, T target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(value, target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsReferenceEqualTo<T>(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asserts that the input value must not be the same instance as the target value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values to compare.</typeparam>
|
||||||
|
/// <param name="value">The input <typeparamref name="T"/> value to test.</param>
|
||||||
|
/// <param name="target">The target <typeparamref name="T"/> value to test for.</param>
|
||||||
|
/// <param name="name">The name of the input parameter being tested.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="value"/> is the same instance as <paramref name="target"/>.</exception>
|
||||||
|
/// <remarks>The method is generic to prevent using it with value types.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void IsReferenceNotEqualTo<T>(T value, T target, [CallerArgumentExpression("value")] string name = "")
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (!ReferenceEquals(value, target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThrowHelper.ThrowArgumentExceptionForIsReferenceNotEqualTo<T>(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotEmpty{T}(Span{T},string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <see cref="Span{T}"/> instance.</typeparam>
|
||||||
|
/// <remarks>This method is needed because <see cref="Span{T}"/> can't be used as a generic type parameter.</remarks>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotEmptyWithSpan<T>(string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(Span<T>).ToTypeString()}) must not be empty.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotEmpty{T}(ReadOnlySpan{T},string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
|
||||||
|
/// <remarks>This method is needed because <see cref="ReadOnlySpan{T}"/> can't be used as a generic type parameter.</remarks>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotEmptyWithReadOnlySpan<T>(string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(ReadOnlySpan<T>).ToTypeString()}) must not be empty.", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotEmpty{T}(T[],string)"/> (or an overload) fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The item of items in the input collection.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotEmpty<T>(string name)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be empty.", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsDefault{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsDefault<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotDefault{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of <see langword="struct"/> value type being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotDefault<T>(string name)
|
||||||
|
where T : struct => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must not be the default value {AssertString(default(T))}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEqualTo<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotEqualTo<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsBitwiseEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input values being compared.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForBitwiseEqualTo<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsLessThan{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsLessThan<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsLessThanOrEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsLessThanOrEqualTo<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsGreaterThan{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThan<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsGreaterThanOrEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsGreaterThanOrEqualTo<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsInRange{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsInRange<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsInRange{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotInRange<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsBetween{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsBetween<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsNotBetween{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotBetween<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsBetweenOrEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsBetweenOrEqualTo<T>(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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsNotBetweenOrEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of values being tested.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeExceptionForIsNotBetweenOrEqualTo<T>(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)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCloseTo(int,int,uint,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCloseTo(int,int,uint,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCloseTo(long,long,ulong,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCloseTo(long,long,ulong,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCloseTo(float,float,float,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCloseTo(float,float,float,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCloseTo(double,double,double,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCloseTo(double,double,double,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCloseTo(nint,nint,nuint,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCloseTo(nint,nint,nuint,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="CanRead"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForCanRead(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support reading.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="CanWrite"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForCanWrite(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support writing.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="CanSeek"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForCanSeek(Stream stream, string name) => throw new ArgumentException($"Stream {AssertString(name)} ({stream.GetType().ToTypeString()}) doesn't support seeking.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsAtStartPosition"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNullOrEmpty"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentNullException"/> or <see cref="ArgumentException"/> when <see cref="IsNotNullOrEmpty"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNullOrWhiteSpace"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotNullOrWhiteSpace"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsEmpty"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsEmpty(string text, string name)
|
||||||
|
=> throw new ArgumentException($"Parameter {AssertString(name)} (string) must be empty, was {AssertString(text)}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotEmpty"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotEmpty(string name)
|
||||||
|
=> throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be empty.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsWhiteSpace"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsWhiteSpace(string text, string name)
|
||||||
|
=> throw new ArgumentException($"Parameter {AssertString(name)} (string) must be whitespace, was {AssertString(text)}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotWhiteSpace"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotWhiteSpace(string text, string name)
|
||||||
|
=> throw new ArgumentException($"Parameter {AssertString(name)} (string) must not be whitespace, was {AssertString(text)}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeEqualTo(string,int,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeNotEqualTo"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeGreaterThan"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeGreaterThanOrEqualTo"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeLessThan"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeLessThanOrEqualTo(string,int,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeEqualTo(string,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasSizeLessThanOrEqualTo(string,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsInRangeFor(int,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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)}.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentOutOfRangeException"/> when <see cref="IsNotInRangeFor(int,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
private partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCompleted"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCompleted"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCompletedSuccessfully"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCompletedSuccessfully"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsFaulted"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotFaulted"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsCanceled"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotCanceled"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasStatusEqualTo"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="HasStatusNotEqualTo"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public partial class Guard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper methods to efficiently throw exceptions.
|
||||||
|
/// </summary>
|
||||||
|
private static partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a formatted representation of the input value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The input <see cref="object"/> to format.</param>
|
||||||
|
/// <returns>A formatted representation of <paramref name="obj"/> to display in error messages.</returns>
|
||||||
|
private static string AssertString(object? obj)
|
||||||
|
=> obj switch
|
||||||
|
{
|
||||||
|
string _ => $"\"{obj}\"",
|
||||||
|
null => "null",
|
||||||
|
_ => $"<{obj}>"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNull{T}(T,string)"/> (where <typeparamref name="T"/> is <see langword="class"/>) fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNull<T>(T value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be null, was {AssertString(value)} ({value!.GetType().ToTypeString()}).", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNull{T}(T,string)"/> (where <typeparamref name="T"/> is <see langword="struct"/>) fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNull<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentNullException"/> when <see cref="IsNotNull{T}(T,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentNullExceptionForIsNotNull<T>(string name) => throw new ArgumentNullException(name, $"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be not null).");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsOfType{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsOfType<T>(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotOfType{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the input value.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotOfType<T>(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be of type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsOfType"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotOfType"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsAssignableToType{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type being checked against.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsAssignableToType<T>(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsNotAssignableToType{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type being checked against.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsNotAssignableToType<T>(object value, string name) => throw new ArgumentException($"Parameter {AssertString(name)} must not be assignable to type {typeof(T).ToTypeString()}, was {value.GetType().ToTypeString()}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsAssignableToType"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsAssignableToType"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsReferenceEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input value being compared.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsReferenceEqualTo<T>(string name)
|
||||||
|
where T : class => throw new ArgumentException($"Parameter {AssertString(name)} ({typeof(T).ToTypeString()}) must be the same instance as the target object.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsReferenceNotEqualTo{T}"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of input value being compared.</typeparam>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsReferenceNotEqualTo<T>(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);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsTrue(bool,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsTrue(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsTrue(bool,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsTrue(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be true, was false: {AssertString(message)}.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsFalse(bool,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsFalse(string name) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true.", name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an <see cref="ArgumentException"/> when <see cref="IsFalse(bool,string,string)"/> fails.
|
||||||
|
/// </summary>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentExceptionForIsFalse(string name, string message) => throw new ArgumentException($"Parameter {AssertString(name)} must be false, was true: {AssertString(message)}.", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public static partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArrayTypeMismatchException<T>() => throw new ArrayTypeMismatchException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArrayTypeMismatchException<T>(string? message) => throw new ArrayTypeMismatchException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArrayTypeMismatchException<T>(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentException<T>() => throw new ArgumentException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentException<T>(string? message) => throw new ArgumentException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentException<T>(string? message, Exception? innerException) => throw new ArgumentException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentException<T>(string? name, string? message) => throw new ArgumentException(message, name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentException<T>(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentNullException<T>() => throw new ArgumentNullException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentNullException<T>(string? name) => throw new ArgumentNullException(name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentNullException<T>(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentNullException<T>(string? name, string? message) => throw new ArgumentNullException(name, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentOutOfRangeException<T>() => throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentOutOfRangeException<T>(string? name) => throw new ArgumentOutOfRangeException(name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentOutOfRangeException<T>(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentOutOfRangeException<T>(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="value">The current argument value.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowArgumentOutOfRangeException<T>(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="COMException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowCOMException<T>() => throw new COMException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowCOMException<T>(string? message) => throw new COMException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowCOMException<T>(string? message, Exception? innerException) => throw new COMException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="error">The HRESULT of the error to include.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowCOMException<T>(string? message, int error) => throw new COMException(message, error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowExternalException<T>() => throw new ExternalException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowExternalException<T>(string? message) => throw new ExternalException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowExternalException<T>(string? message, Exception? innerException) => throw new ExternalException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="error">The HRESULT of the error to include.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowExternalException<T>(string? message, int error) => throw new ExternalException(message, error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="FormatException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowFormatException<T>() => throw new FormatException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="FormatException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowFormatException<T>(string? message) => throw new FormatException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="FormatException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowFormatException<T>(string? message, Exception? innerException) => throw new FormatException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInsufficientMemoryException<T>() => throw new InsufficientMemoryException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInsufficientMemoryException<T>(string? message) => throw new InsufficientMemoryException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInsufficientMemoryException<T>(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidDataException<T>() => throw new InvalidDataException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidDataException<T>(string? message) => throw new InvalidDataException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidDataException<T>(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidOperationException<T>() => throw new InvalidOperationException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidOperationException<T>(string? message) => throw new InvalidOperationException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowInvalidOperationException<T>(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowLockRecursionException<T>() => throw new LockRecursionException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowLockRecursionException<T>(string? message) => throw new LockRecursionException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowLockRecursionException<T>(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingFieldException<T>() => throw new MissingFieldException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingFieldException<T>(string? message) => throw new MissingFieldException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingFieldException<T>(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="fieldName">The target field being retrieved.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingFieldException<T>(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMemberException<T>() => throw new MissingMemberException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMemberException<T>(string? message) => throw new MissingMemberException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMemberException<T>(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="memberName">The target member being retrieved.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMemberException<T>(string? className, string? memberName) => throw new MissingMemberException(className, memberName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMethodException<T>() => throw new MissingMethodException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMethodException<T>(string? message) => throw new MissingMethodException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMethodException<T>(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="methodName">The target method being retrieved.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowMissingMethodException<T>(string? className, string? methodName) => throw new MissingMethodException(className, methodName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowNotSupportedException<T>() => throw new NotSupportedException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowNotSupportedException<T>(string? message) => throw new NotSupportedException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowNotSupportedException<T>(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowObjectDisposedException<T>(string? objectName) => throw new ObjectDisposedException(objectName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowObjectDisposedException<T>(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowObjectDisposedException<T>(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>() => throw new OperationCanceledException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>(string? message) => throw new OperationCanceledException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>(CancellationToken token) => throw new OperationCanceledException(token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>(string? message, CancellationToken token) => throw new OperationCanceledException(message, token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowOperationCanceledException<T>(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowPlatformNotSupportedException<T>() => throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowPlatformNotSupportedException<T>(string? message) => throw new PlatformNotSupportedException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowPlatformNotSupportedException<T>(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowSynchronizationLockException<T>() => throw new SynchronizationLockException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowSynchronizationLockException<T>(string? message) => throw new SynchronizationLockException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowSynchronizationLockException<T>(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowTimeoutException<T>() => throw new TimeoutException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowTimeoutException<T>(string? message) => throw new TimeoutException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowTimeoutException<T>(string? message, Exception? innerException) => throw new TimeoutException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowUnauthorizedAccessException<T>() => throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowUnauthorizedAccessException<T>(string? message) => throw new UnauthorizedAccessException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowUnauthorizedAccessException<T>(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with no parameters.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowWin32Exception<T>() => throw new Win32Exception();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="error">The Win32 error code associated with this exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowWin32Exception<T>(int error) => throw new Win32Exception(error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="error">The Win32 error code associated with this exception.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowWin32Exception<T>(int error, string? message) => throw new Win32Exception(error, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowWin32Exception<T>(string? message) => throw new Win32Exception(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of expected result.</typeparam>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
/// <returns>This method always throws, so it actually never returns a value.</returns>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static T ThrowWin32Exception<T>(string? message, Exception? innerException) => throw new Win32Exception(message, innerException);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper methods to efficiently throw exceptions.
|
||||||
|
/// </summary>
|
||||||
|
public static partial class ThrowHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArrayTypeMismatchException() => throw new ArrayTypeMismatchException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArrayTypeMismatchException(string? message) => throw new ArrayTypeMismatchException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArrayTypeMismatchException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArrayTypeMismatchException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArrayTypeMismatchException(string? message, Exception? innerException) => throw new ArrayTypeMismatchException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentException() => throw new ArgumentException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentException(string? message) => throw new ArgumentException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentException(string? message, Exception? innerException) => throw new ArgumentException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentException(string? name, string? message) => throw new ArgumentException(message, name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentException(string? name, string? message, Exception? innerException) => throw new ArgumentException(message, name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentNullException() => throw new ArgumentNullException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentNullException(string? name) => throw new ArgumentNullException(name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentNullException(string? name, Exception? innerException) => throw new ArgumentNullException(name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentNullException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentNullException(string? name, string? message) => throw new ArgumentNullException(name, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeException(string? name) => throw new ArgumentOutOfRangeException(name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeException(string? name, Exception? innerException) => throw new ArgumentOutOfRangeException(name, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeException(string? name, string? message) => throw new ArgumentOutOfRangeException(name, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ArgumentOutOfRangeException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The argument name.</param>
|
||||||
|
/// <param name="value">The current argument value.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowArgumentOutOfRangeException(string? name, object? value, string? message) => throw new ArgumentOutOfRangeException(name, value, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="COMException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowCOMException() => throw new COMException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowCOMException(string? message) => throw new COMException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowCOMException(string? message, Exception? innerException) => throw new COMException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="COMException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="error">The HRESULT of the error to include.</param>
|
||||||
|
/// <exception cref="COMException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowCOMException(string? message, int error) => throw new COMException(message, error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="ExternalException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowExternalException() => throw new ExternalException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowExternalException(string? message) => throw new ExternalException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowExternalException(string? message, Exception? innerException) => throw new ExternalException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ExternalException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The argument name.</param>
|
||||||
|
/// <param name="error">The HRESULT of the error to include.</param>
|
||||||
|
/// <exception cref="ExternalException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowExternalException(string? message, int error) => throw new ExternalException(message, error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="FormatException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowFormatException() => throw new FormatException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="FormatException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowFormatException(string? message) => throw new FormatException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="FormatException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="FormatException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowFormatException(string? message, Exception? innerException) => throw new FormatException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInsufficientMemoryException() => throw new InsufficientMemoryException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInsufficientMemoryException(string? message) => throw new InsufficientMemoryException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InsufficientMemoryException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InsufficientMemoryException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInsufficientMemoryException(string? message, Exception? innerException) => throw new InsufficientMemoryException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidDataException() => throw new InvalidDataException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidDataException(string? message) => throw new InvalidDataException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidDataException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InvalidDataException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidDataException(string? message, Exception? innerException) => throw new InvalidDataException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidOperationException() => throw new InvalidOperationException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidOperationException(string? message) => throw new InvalidOperationException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="InvalidOperationException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowInvalidOperationException(string? message, Exception? innerException) => throw new InvalidOperationException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowLockRecursionException() => throw new LockRecursionException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowLockRecursionException(string? message) => throw new LockRecursionException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="LockRecursionException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="LockRecursionException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowLockRecursionException(string? message, Exception? innerException) => throw new LockRecursionException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingFieldException() => throw new MissingFieldException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingFieldException(string? message) => throw new MissingFieldException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingFieldException(string? message, Exception? innerException) => throw new MissingFieldException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingFieldException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="fieldName">The target field being retrieved.</param>
|
||||||
|
/// <exception cref="MissingFieldException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingFieldException(string? className, string? fieldName) => throw new MissingFieldException(className, fieldName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMemberException() => throw new MissingMemberException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMemberException(string? message) => throw new MissingMemberException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMemberException(string? message, Exception? innerException) => throw new MissingMemberException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMemberException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="memberName">The target member being retrieved.</param>
|
||||||
|
/// <exception cref="MissingMemberException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMemberException(string? className, string? memberName) => throw new MissingMemberException(className, memberName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMethodException() => throw new MissingMethodException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMethodException(string? message) => throw new MissingMethodException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMethodException(string? message, Exception? innerException) => throw new MissingMethodException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="MissingMethodException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="className">The target class being inspected.</param>
|
||||||
|
/// <param name="methodName">The target method being retrieved.</param>
|
||||||
|
/// <exception cref="MissingMethodException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowMissingMethodException(string? className, string? methodName) => throw new MissingMethodException(className, methodName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowNotSupportedException() => throw new NotSupportedException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowNotSupportedException(string? message) => throw new NotSupportedException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="NotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowNotSupportedException(string? message, Exception? innerException) => throw new NotSupportedException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowObjectDisposedException(string? objectName) => throw new ObjectDisposedException(objectName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowObjectDisposedException(string? objectName, Exception? innerException) => throw new ObjectDisposedException(objectName, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="ObjectDisposedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectName">The name of the disposed object.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="ObjectDisposedException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowObjectDisposedException(string? objectName, string? message) => throw new ObjectDisposedException(objectName, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException() => throw new OperationCanceledException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException(string? message) => throw new OperationCanceledException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException(string? message, Exception? innerException) => throw new OperationCanceledException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException(CancellationToken token) => throw new OperationCanceledException(token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException(string? message, CancellationToken token) => throw new OperationCanceledException(message, token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="OperationCanceledException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <param name="token">The <see cref="CancellationToken"/> in use.</param>
|
||||||
|
/// <exception cref="OperationCanceledException">Thrown with the specified parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowOperationCanceledException(string? message, Exception? innerException, CancellationToken token) => throw new OperationCanceledException(message, innerException, token);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowPlatformNotSupportedException() => throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowPlatformNotSupportedException(string? message) => throw new PlatformNotSupportedException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="PlatformNotSupportedException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="PlatformNotSupportedException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowPlatformNotSupportedException(string? message, Exception? innerException) => throw new PlatformNotSupportedException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowSynchronizationLockException() => throw new SynchronizationLockException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowSynchronizationLockException(string? message) => throw new SynchronizationLockException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="SynchronizationLockException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="SynchronizationLockException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowSynchronizationLockException(string? message, Exception? innerException) => throw new SynchronizationLockException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowTimeoutException() => throw new TimeoutException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowTimeoutException(string? message) => throw new TimeoutException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="TimeoutException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="TimeoutException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowTimeoutException(string? message, Exception? innerException) => throw new TimeoutException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowUnauthorizedAccessException() => throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowUnauthorizedAccessException(string? message) => throw new UnauthorizedAccessException(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="UnauthorizedAccessException"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="UnauthorizedAccessException">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowUnauthorizedAccessException(string? message, Exception? innerException) => throw new UnauthorizedAccessException(message, innerException);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with no parameters.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowWin32Exception() => throw new Win32Exception();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">The Win32 error code associated with this exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowWin32Exception(int error) => throw new Win32Exception(error);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">The Win32 error code associated with this exception.</param>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowWin32Exception(int error, string? message) => throw new Win32Exception(error, message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowWin32Exception(string? message) => throw new Win32Exception(message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a new <see cref="Win32Exception"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to include in the exception.</param>
|
||||||
|
/// <param name="innerException">The inner <see cref="Exception"/> to include.</param>
|
||||||
|
/// <exception cref="Win32Exception">Thrown with the specified parameter.</exception>
|
||||||
|
[DoesNotReturn]
|
||||||
|
public static void ThrowWin32Exception(string? message, Exception? innerException) => throw new Win32Exception(message, innerException);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generic overload of Equals to avoid boxing. Makes use of function pointers for best performance and does not throw on null for reference types.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe bool Equals<T>([AllowNull] this T @this, [AllowNull] T other)
|
||||||
|
=> FunctionPointers.Equals<T>.Default(@this!, other!);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe bool Equals<T>([AllowNull] this ref T @this, [AllowNull] ref T other)
|
||||||
|
where T : struct // required by the compiler for 'this ref'
|
||||||
|
=> FunctionPointers.EqualsByRef<T>.Default(ref @this!, ref other!);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe bool EqualsByRef<T>([AllowNull] ref T @this, [AllowNull] ref T other)
|
||||||
|
=> FunctionPointers.EqualsByRef<T>.Default(ref @this!, ref other!);
|
||||||
|
}
|
||||||
@@ -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<Delegate>? TargetMethodGroups => null;
|
||||||
|
public virtual Expression<Action>? TargetMethod => null;
|
||||||
|
public virtual IEnumerable<Expression<Action>>? TargetMethods => null;
|
||||||
|
public virtual MethodBase TargetMethodInfo => TargetMethod != null ? SymbolExtensions.GetMethodInfo(TargetMethod)
|
||||||
|
: TargetMethodGroup?.Method ?? throw new MissingMethodException(GetType().ToString());
|
||||||
|
public virtual IEnumerable<MethodBase> 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<HarmonyReversePatch>() && !m.HasAttribute<HarmonyTranspiler>()));
|
||||||
|
public virtual MethodInfo ReversePatchTranspilerMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "REVERSEPATCHTRANSPILER" || (m.HasAttribute<HarmonyTranspiler>() && m.HasAttribute<HarmonyReversePatch>()));
|
||||||
|
public virtual MethodInfo PrefixMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "PREFIX" || m.HasAttribute<HarmonyPrefix>());
|
||||||
|
public virtual MethodInfo PostfixMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "POSTFIX" || m.HasAttribute<HarmonyPostfix>());
|
||||||
|
public virtual MethodInfo TranspilerMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "TRANSPILER" || (m.HasAttribute<HarmonyTranspiler>() && !m.HasAttribute<HarmonyReversePatch>()));
|
||||||
|
public virtual MethodInfo FinalizerMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "FINALIZER" || m.HasAttribute<HarmonyFinalizer>());
|
||||||
|
public virtual MethodInfo PrepareMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "PREPARE" || m.HasAttribute<HarmonyPrepare>());
|
||||||
|
public virtual MethodInfo CleanupMethodInfo => GetType().GetMethods(AccessTools.allDeclared)
|
||||||
|
.FirstOrDefault(m => m.Name.ToUpperInvariant() == "CLEANUP" || m.HasAttribute<HarmonyCleanup>());
|
||||||
|
|
||||||
|
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<HarmonyPriority>()?.info.priority ?? Priority.Normal;
|
||||||
|
|
||||||
|
public static T Get<T>() => TryGet<T>() ?? throw new KeyNotFoundException($"Couldn't find FishPatch or IHasFishPatch class {typeof(T).Name}");
|
||||||
|
public static T? TryGet<T>()
|
||||||
|
{
|
||||||
|
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<FishPatch> patches)
|
||||||
|
{
|
||||||
|
foreach (var patch in patches)
|
||||||
|
patch.TryPatch();
|
||||||
|
}
|
||||||
|
public static void UnpatchAll(this IEnumerable<FishPatch> patches)
|
||||||
|
{
|
||||||
|
foreach (var patch in patches)
|
||||||
|
patch.TryUnpatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FishPatchHolder : IExposable, IEnumerable<FishPatch>
|
||||||
|
{
|
||||||
|
public Dictionary<Type, FishPatch> All => _all;
|
||||||
|
public T Get<T>() where T : FishPatch => (T)All[typeof(T)];
|
||||||
|
public FishPatch Get(Type type) => All[type];
|
||||||
|
public T? TryGet<T>() 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<FishPatch> GetEnumerator() => All.Values.GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => All.Values.GetEnumerator();
|
||||||
|
|
||||||
|
private Dictionary<Type, FishPatch> _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;
|
||||||
|
}*/
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
|||||||
|
// 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 System;
|
||||||
|
global using System.Collections.Generic;
|
||||||
|
global using System.Reflection;
|
||||||
|
global using HarmonyLib;
|
||||||
|
global using FisheryLib.Utility.Diagnostics;
|
||||||
|
global using CodeInstructions = System.Collections.Generic.IEnumerable<HarmonyLib.CodeInstruction>;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
|
[assembly: AllowPartiallyTrustedCallers]
|
||||||
|
[assembly: SecurityTransparent]
|
||||||
|
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]
|
||||||
|
|
||||||
|
/*namespace FisheryLib;
|
||||||
|
public class Fishery : Harmony
|
||||||
|
{
|
||||||
|
/// <summary>Creates a new Fishery instance</summary>
|
||||||
|
/// <param name="id">A unique identifier (you choose your own)</param>
|
||||||
|
/// <returns>A Fishery instance</returns>
|
||||||
|
public Fishery(string id) : base(id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Creates a patch class processor from an annotated class</summary>
|
||||||
|
/// <param name="type">The class/type</param>
|
||||||
|
/// <returns>A new <see cref="PatchClassProcessor"/> instance</returns>
|
||||||
|
public new FisheryPatchClassProcessor CreateClassProcessor(Type type) => new(this, type);
|
||||||
|
|
||||||
|
/// <summary>Creates patches by manually specifying the methods</summary>
|
||||||
|
/// <param name="original">The original method/constructor</param>
|
||||||
|
/// <param name="prefix">An optional prefix method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="postfix">An optional postfix method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="infix">An optional infix method wrapped in a <see cref="InfixMethod"/> object</param>
|
||||||
|
/// <param name="transpiler">An optional transpiler method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="finalizer">An optional finalizer method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <returns>The replacement method that was created to patch the original method</returns>
|
||||||
|
public MethodInfo Patch(MethodBase original, HarmonyMethod? prefix = null, HarmonyMethod? postfix = null, InfixMethod? infix = null, HarmonyMethod? transpiler = null, HarmonyMethod? finalizer = null)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(original, nameof(original));
|
||||||
|
|
||||||
|
return HarmonyPatchExtensions.Patch(this, original, prefix, postfix, infix, transpiler, finalizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Searches the current assembly for Harmony and Fishery annotations, using them to create patches</summary>
|
||||||
|
/// <remarks>This method can fail to use the correct assembly when being inlined. It calls StackTrace.GetFrame(1) which can point to the wrong method/assembly. If you are unsure or run into problems, use <code>PatchAll(Assembly.GetExecutingAssembly())</code> instead.</remarks>
|
||||||
|
public new void PatchAll() => PatchAll(UtilityF.GetCallingAssembly());
|
||||||
|
|
||||||
|
/// <summary>Searches an assembly for Harmony annotations and uses them to create patches</summary>
|
||||||
|
/// <param name="assembly">The assembly</param>
|
||||||
|
public new void PatchAll(Assembly assembly)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(assembly, nameof(assembly));
|
||||||
|
|
||||||
|
foreach (var type in AccessTools.GetTypesFromAssembly(assembly))
|
||||||
|
CreateClassProcessor(type).Patch();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>FisheryLib</RootNamespace>
|
||||||
|
<AssemblyName>1Fishery</AssemblyName>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<!--PublicizeAsReferenceAssemblies>false</PublicizeAsReferenceAssemblies-->
|
||||||
|
<Authors>bradson</Authors>
|
||||||
|
<Copyright>Copyright (c) 2022 bradson</Copyright>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
||||||
|
<AnalysisLevel>preview-all</AnalysisLevel>
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>5</WarningLevel>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
<Configurations>v1.3;v1.4</Configurations>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(Configuration)' == 'v1.3'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\..\1.3\Assemblies\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.3.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
<When Condition="'$(Configuration)' == 'v1.4'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>..\..\1.4\Assemblies\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.4.*-*" />
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Lib.Harmony" Version="2.*" ExcludeAssets="runtime" />
|
||||||
|
<PackageReference Include="Nullable" Version="1.*" />
|
||||||
|
<PackageReference Include="IndexRange" Version="1.*" />
|
||||||
|
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.*" />
|
||||||
|
<PackageReference Include="Krafs.Publicizer" Version="2.*" />
|
||||||
|
<Publicize Include="Assembly-CSharp;0Harmony" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.buckets" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.entries" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2.version" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.Dictionary`2+Entry" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.List`1._items" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.List`1._version" />
|
||||||
|
<Publicize Include="mscorlib:System.Collections.Generic.List`1._size" />
|
||||||
|
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast" />
|
||||||
|
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong" />
|
||||||
|
<Publicize Include="mscorlib:System.Runtime.CompilerServices.JitHelpers.UnsafeCast" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\..\LICENSE">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath></PackagePath>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.1.32120.378
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fishery", "Fishery.csproj", "{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}"
|
||||||
|
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
|
||||||
|
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.ActiveCfg = v1.3|Any CPU
|
||||||
|
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.3|Any CPU.Build.0 = v1.3|Any CPU
|
||||||
|
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.ActiveCfg = v1.4|Any CPU
|
||||||
|
{B5B38CBB-F8EE-451E-A05B-9ED9B03784D2}.v1.4|Any CPU.Build.0 = v1.4|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {77D96407-032A-4609-995A-EA52611536DC}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
/// <summary>A PatchClassProcessor used to turn <see cref="HarmonyAttribute"/> and Fishery attributes on a class/type into patches</summary>
|
||||||
|
public class FisheryPatchClassProcessor : PatchClassProcessor
|
||||||
|
{
|
||||||
|
new readonly HarmonyMethod? containerAttributes;
|
||||||
|
new readonly Dictionary<Type, MethodInfo>? auxilaryMethods;
|
||||||
|
|
||||||
|
new readonly List<AttributePatch>? patchMethods;
|
||||||
|
|
||||||
|
new static readonly List<Type> auxilaryTypes = new()
|
||||||
|
{
|
||||||
|
typeof(HarmonyPrepare),
|
||||||
|
typeof(HarmonyCleanup),
|
||||||
|
typeof(HarmonyTargetMethod),
|
||||||
|
typeof(HarmonyTargetMethods)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>Creates a patch class processor by pointing out a class. Similar to PatchAll() but without searching through all classes. This version supports attributes added by Fishery.</summary>
|
||||||
|
/// <param name="instance">The Harmony instance</param>
|
||||||
|
/// <param name="type">The class to process (need to have at least a [HarmonyPatch] attribute)</param>
|
||||||
|
public FisheryPatchClassProcessor(Harmony instance, Type type) : base(instance, type)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(instance, nameof(instance));
|
||||||
|
Guard.IsNotNull(type, nameof(type));
|
||||||
|
//this.instance = instance;
|
||||||
|
//containerType = type;
|
||||||
|
|
||||||
|
if (HarmonyMethodExtensions.GetFromType(type) is not { Count: not 0 } harmonyAttributes)
|
||||||
|
return;
|
||||||
|
|
||||||
|
containerAttributes = HarmonyMethod.Merge(harmonyAttributes);
|
||||||
|
containerAttributes.methodType ??= MethodType.Normal; // MethodType default is Normal
|
||||||
|
|
||||||
|
auxilaryMethods = new();
|
||||||
|
foreach (var auxType in auxilaryTypes)
|
||||||
|
{
|
||||||
|
var method = PatchTools.GetPatchMethod(containerType, auxType.FullName);
|
||||||
|
if (method is object)
|
||||||
|
auxilaryMethods[auxType] = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchMethods = PatchTools.GetPatchMethods(containerType);
|
||||||
|
foreach (var patchMethod in patchMethods)
|
||||||
|
{
|
||||||
|
var method = patchMethod.info.method;
|
||||||
|
patchMethod.info = containerAttributes.Merge(patchMethod.info);
|
||||||
|
patchMethod.info.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var attribute in type.GetCustomAttributes())
|
||||||
|
{
|
||||||
|
if (attribute is InfixAttribute infixAttribute)
|
||||||
|
{
|
||||||
|
var infixMethod = new InfixMethod(null!, infixAttribute.InfixTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AttributePatch> GetPatchMethods(Type type)
|
||||||
|
{
|
||||||
|
var attributePatches = new List<AttributePatch>();
|
||||||
|
var methodInfos = AccessTools.GetDeclaredMethods(type);
|
||||||
|
for (var i = 0; i < methodInfos.Count; i++)
|
||||||
|
{
|
||||||
|
if (AttributePatch.Create(methodInfos[i]) is { } attributePatch)
|
||||||
|
attributePatches.Add(attributePatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributePatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributePatch? CreateInfixAttributePatch(MethodInfo patch)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(patch, nameof(patch));
|
||||||
|
|
||||||
|
var customAttributes = patch.GetCustomAttributes(inherit: true);
|
||||||
|
var patchType = GetInfixPatchType(patch.Name, customAttributes);
|
||||||
|
|
||||||
|
if (patchType is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (patchType != FisheryPatchType.ReversePatch && !patch.IsStatic)
|
||||||
|
throw new ArgumentException($"Patch method {patch.FullDescription()} must be static");
|
||||||
|
|
||||||
|
var harmonyAttributes = new List<HarmonyMethod>();
|
||||||
|
foreach (var attr in customAttributes)
|
||||||
|
{
|
||||||
|
if (attr.GetType().BaseType.FullName == AttributePatch.harmonyAttributeName)
|
||||||
|
{
|
||||||
|
harmonyAttributes.Add(
|
||||||
|
AccessTools.MakeDeepCopy<HarmonyMethod>(
|
||||||
|
AccessTools.Field(attr.GetType(), nameof(HarmonyAttribute.info)).GetValue(attr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var harmonyMethod = HarmonyMethod.Merge(harmonyAttributes);
|
||||||
|
harmonyMethod.method = patch;
|
||||||
|
return new AttributePatch
|
||||||
|
{
|
||||||
|
info = harmonyMethod,
|
||||||
|
type = (HarmonyPatchType)patchType //<--------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> HarmonyFields { get; } = typeof(HarmonyMethod).GetFields(AccessTools.allDeclared).Select(f => f.Name).Where(s => s != "method");
|
||||||
|
|
||||||
|
public static HarmonyMethod Merge(List<HarmonyMethod> attributes)
|
||||||
|
{
|
||||||
|
var harmonyMethod = new HarmonyMethod();
|
||||||
|
if (attributes == null)
|
||||||
|
{
|
||||||
|
return harmonyMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultTrv = Traverse.Create(harmonyMethod);
|
||||||
|
attributes.ForEach(delegate (HarmonyMethod attribute)
|
||||||
|
{
|
||||||
|
var trv = Traverse.Create(attribute);
|
||||||
|
foreach (var f in HarmonyFields)
|
||||||
|
{
|
||||||
|
var value = trv.Field(f).GetValue();
|
||||||
|
if (value != null && (f != "priority" || (int)value != -1))
|
||||||
|
{
|
||||||
|
SetValue(resultTrv, f, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return harmonyMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetValue(Traverse trv, string name, object val)
|
||||||
|
{
|
||||||
|
if (val != null)
|
||||||
|
{
|
||||||
|
var traverse = trv.Field(name);
|
||||||
|
if (name is "methodType" or "reversePatchType")
|
||||||
|
{
|
||||||
|
val = Enum.ToObject(Nullable.GetUnderlyingType(traverse.GetValueType()), (int)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse.SetValue(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FisheryPatchType? GetInfixPatchType(string methodName, object[] allAttributes)
|
||||||
|
{
|
||||||
|
var hashSet = new HashSet<string>();
|
||||||
|
for (var i = 0; i < allAttributes.Length; i++)
|
||||||
|
{
|
||||||
|
var name = allAttributes[i].GetType().FullName;
|
||||||
|
if (StartsWithAny(name, AttributePrefixes))
|
||||||
|
hashSet.Add(name.ToUpperInvariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
FisheryPatchType? result = null;
|
||||||
|
var array = AttributePatch.allPatchTypes;
|
||||||
|
for (var i = 0; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
var value = array[i];
|
||||||
|
var text = value.ToString().ToUpperInvariant();
|
||||||
|
|
||||||
|
if (text == methodName.ToUpperInvariant()
|
||||||
|
|| hashSet.Overlaps(CombineWithAttributePrefixes(text)))
|
||||||
|
{
|
||||||
|
result = (FisheryPatchType)value; //<------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (string Namespace, string Prefix)[] AttributePrefixInfoTuples { get; } = new[] { (nameof(HarmonyLib), "Harmony"), (nameof(FisheryLib), "Fishery"), (nameof(FisheryLib), "Infix") };
|
||||||
|
private static string[] AttributePrefixes { get; } = Array.ConvertAll(AttributePrefixInfoTuples, t => t.Prefix);
|
||||||
|
private static string[] AttributePrefixesWithNamespace { get; } = Array.ConvertAll(AttributePrefixInfoTuples, t => $"{t.Namespace}.{t.Prefix}");
|
||||||
|
private static IEnumerable<string> CombineWithAttributePrefixes(string text)
|
||||||
|
{
|
||||||
|
foreach (var prefix in AttributePrefixesWithNamespace)
|
||||||
|
yield return prefix + text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool StartsWithAny(string text, string[] values)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
if (text.StartsWith(values[i]))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FisheryPatchType
|
||||||
|
{
|
||||||
|
All,
|
||||||
|
Prefix,
|
||||||
|
Postfix,
|
||||||
|
Infix,
|
||||||
|
Transpiler,
|
||||||
|
Finalizer,
|
||||||
|
ReversePatch
|
||||||
|
}*/
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
public static class Convert<TFrom> where TFrom : IConvertible
|
||||||
|
{
|
||||||
|
public static class To<TTo>
|
||||||
|
{
|
||||||
|
public static readonly unsafe delegate*<TFrom, IFormatProvider, TTo> Default = Convert.GetDefaultConverter<TFrom, TTo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used when TFrom isn't a known sealed type, i.e. with just the IConvertible interface
|
||||||
|
/// </summary>
|
||||||
|
internal static class Fallback<TTo>
|
||||||
|
{
|
||||||
|
internal static readonly Func<TFrom, IFormatProvider, TTo> Func = Convert.GetDefaultConverterFunc<TFrom, TTo>();
|
||||||
|
internal static TTo FallbackMethod(TFrom from, IFormatProvider provider) => Func(from, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class Convert
|
||||||
|
{
|
||||||
|
private static MethodInfo GetConverterMethod<TFrom>(Type to) where TFrom : IConvertible
|
||||||
|
{
|
||||||
|
var info = typeof(TFrom).GetMethod(GetConvertMethodName(to));
|
||||||
|
if (info.GetParameters().Length > 1)
|
||||||
|
{
|
||||||
|
info = typeof(Convert)
|
||||||
|
.GetMethod(nameof(ConvertToType), AccessTools.allDeclared)
|
||||||
|
.MakeGenericMethod(new[] { typeof(TFrom), to });
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Func<TFrom, IFormatProvider, TTo> GetDefaultConverterFunc<TFrom, TTo>() where TFrom : IConvertible
|
||||||
|
=> (Func<TFrom, IFormatProvider, TTo>)GetConverterMethod<TFrom>(typeof(TTo))
|
||||||
|
.CreateDelegate(typeof(Func<TFrom, IFormatProvider, TTo>));
|
||||||
|
|
||||||
|
internal static unsafe delegate*<TFrom, IFormatProvider, TTo> GetDefaultConverter<TFrom, TTo>() where TFrom : IConvertible
|
||||||
|
=> !typeof(TFrom).IsValueType && (!typeof(TFrom).IsSealed || typeof(TFrom).IsInterface || typeof(TFrom).IsAbstract)
|
||||||
|
? &Convert<TFrom>.Fallback<TTo>.FallbackMethod
|
||||||
|
: (delegate*<TFrom, IFormatProvider, TTo>)GetConverterMethod<TFrom>(typeof(TTo))
|
||||||
|
.MethodHandle.GetFunctionPointer();
|
||||||
|
|
||||||
|
private static TTo ConvertToType<TFrom, TTo>(TFrom from, IFormatProvider provider) where TFrom : IConvertible
|
||||||
|
=> (TTo)from.ToType(typeof(TTo), provider);
|
||||||
|
|
||||||
|
private static string GetConvertMethodName(Type type)
|
||||||
|
=> type == typeof(bool)
|
||||||
|
? nameof(IConvertible.ToBoolean)
|
||||||
|
: type == typeof(char)
|
||||||
|
? nameof(IConvertible.ToChar)
|
||||||
|
: type == typeof(sbyte)
|
||||||
|
? nameof(IConvertible.ToSByte)
|
||||||
|
: type == typeof(byte)
|
||||||
|
? nameof(IConvertible.ToByte)
|
||||||
|
: type == typeof(short)
|
||||||
|
? nameof(IConvertible.ToInt16)
|
||||||
|
: type == typeof(ushort)
|
||||||
|
? nameof(IConvertible.ToUInt16)
|
||||||
|
: type == typeof(int)
|
||||||
|
? nameof(IConvertible.ToInt32)
|
||||||
|
: type == typeof(uint)
|
||||||
|
? nameof(IConvertible.ToUInt32)
|
||||||
|
: type == typeof(long)
|
||||||
|
? nameof(IConvertible.ToInt64)
|
||||||
|
: type == typeof(ulong)
|
||||||
|
? nameof(IConvertible.ToUInt64)
|
||||||
|
: type == typeof(float)
|
||||||
|
? nameof(IConvertible.ToSingle)
|
||||||
|
: type == typeof(double)
|
||||||
|
? nameof(IConvertible.ToDouble)
|
||||||
|
: type == typeof(decimal)
|
||||||
|
? nameof(IConvertible.ToDecimal)
|
||||||
|
: type == typeof(DateTime)
|
||||||
|
? nameof(IConvertible.ToDateTime)
|
||||||
|
: type == typeof(string)
|
||||||
|
? nameof(IConvertible.ToString)
|
||||||
|
//: type == typeof(object)
|
||||||
|
//? value
|
||||||
|
: nameof(IConvertible.ToType);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
public static class Equals<T>
|
||||||
|
{
|
||||||
|
public static readonly unsafe delegate*<T, T, bool> Default = (delegate*<T, T, bool>)FunctionPointers.Equals.MakeDelegate(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Equals
|
||||||
|
{
|
||||||
|
public static class Methods
|
||||||
|
{
|
||||||
|
public static bool Byte(byte x, byte y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Int(int x, int y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Uint(uint x, uint y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Ushort(ushort x, ushort y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool IntPtr(IntPtr x, IntPtr y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool String(string x, string y)
|
||||||
|
=> string.Equals(x, y);
|
||||||
|
|
||||||
|
public static unsafe bool VoidPtr(void* x, void* y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool RuntimeFieldHandle(RuntimeFieldHandle x, RuntimeFieldHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool RuntimeTypeHandle(RuntimeTypeHandle x, RuntimeTypeHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool RuntimeMethodHandle(RuntimeMethodHandle x, RuntimeMethodHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool Enum<T>(T x, T y) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCast(x) == JitHelpers.UnsafeEnumCast(y);
|
||||||
|
|
||||||
|
public static bool LongEnum<T>(T x, T y) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCastLong(x) == JitHelpers.UnsafeEnumCastLong(y);
|
||||||
|
|
||||||
|
public static bool EquatableValueType<T>(T x, T y) where T : struct, IEquatable<T>
|
||||||
|
=> x.Equals(y);
|
||||||
|
|
||||||
|
public static bool Nullable<T>(T? x, T? y) where T : struct, IEquatable<T>
|
||||||
|
=> x.HasValue
|
||||||
|
? y.HasValue && x.Value.Equals(y.Value)
|
||||||
|
: !y.HasValue;
|
||||||
|
|
||||||
|
public static bool EquatableReferenceType<T>(T x, T y) where T : IEquatable<T>
|
||||||
|
=> x != null
|
||||||
|
? y != null && x.Equals(y)
|
||||||
|
: y == null;
|
||||||
|
|
||||||
|
public static bool Reference<T>(T x, T y) where T : class
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Object<T>(T x, T y)
|
||||||
|
=> x != null
|
||||||
|
? y != null && x.Equals(y)
|
||||||
|
: y == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static unsafe IntPtr MakeDelegate(Type type)
|
||||||
|
=> _equalsMethods.Where(m => !m.IsGenericMethod)
|
||||||
|
.FirstOrDefault(m
|
||||||
|
=> m.GetParameters().First().ParameterType == type)
|
||||||
|
is { } specializedMethod
|
||||||
|
? specializedMethod.GetFunctionPointer()
|
||||||
|
: type.IsAssignableTo(typeof(IEquatable<>), type)
|
||||||
|
? GetMethod(
|
||||||
|
type.IsValueType
|
||||||
|
? nameof(Methods.EquatableValueType)
|
||||||
|
: nameof(Methods.EquatableReferenceType))
|
||||||
|
.MakeGenericMethod(type)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer()
|
||||||
|
: type.IsNullable(out var genericArgument)
|
||||||
|
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||||
|
? GetMethod(nameof(Methods.Nullable)).MakeGenericMethod(genericArgument)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer()
|
||||||
|
: GetMethod(
|
||||||
|
type.IsEnum
|
||||||
|
? Type.GetTypeCode(Enum.GetUnderlyingType(type))
|
||||||
|
switch
|
||||||
|
{
|
||||||
|
TypeCode.Int16
|
||||||
|
or TypeCode.SByte
|
||||||
|
or TypeCode.Byte
|
||||||
|
or TypeCode.UInt16
|
||||||
|
or TypeCode.Int32
|
||||||
|
or TypeCode.UInt32 => nameof(Methods.Enum),
|
||||||
|
TypeCode.Int64
|
||||||
|
or TypeCode.UInt64 => nameof(Methods.LongEnum),
|
||||||
|
_ => ThrowHelper.ThrowNotSupportedException<string>()
|
||||||
|
}
|
||||||
|
: nameof(Methods.Object)
|
||||||
|
).MakeGenericMethod(type)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer();
|
||||||
|
|
||||||
|
private static MethodInfo GetMethod(string name)
|
||||||
|
=> Array.Find(_equalsMethods, m => m.Name == name);
|
||||||
|
|
||||||
|
private static MethodInfo[] _equalsMethods
|
||||||
|
= typeof(Methods)
|
||||||
|
.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m
|
||||||
|
=> m.ReturnType == typeof(bool)
|
||||||
|
&& m.GetParameters().Length == 2)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
//internal delegate bool EqualsDelegate<T>(T x, T y);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
public static class EqualsByRef<T>
|
||||||
|
{
|
||||||
|
public static readonly unsafe delegate*<ref T, ref T, bool> Default = (delegate*<ref T, ref T, bool>)EqualsByRef.MakeDelegate(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EqualsByRef
|
||||||
|
{
|
||||||
|
public static class Methods
|
||||||
|
{
|
||||||
|
public static bool Byte(ref byte x, ref byte y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Int(ref int x, ref int y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Uint(ref uint x, ref uint y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Ushort(ref ushort x, ref ushort y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool IntPtr(ref IntPtr x, ref IntPtr y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool String(ref string x, ref string y)
|
||||||
|
=> string.Equals(x, y);
|
||||||
|
|
||||||
|
public static unsafe bool VoidPtr(ref void* x, ref void* y)
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool RuntimeFieldHandle(ref RuntimeFieldHandle x, ref RuntimeFieldHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool RuntimeTypeHandle(ref RuntimeTypeHandle x, ref RuntimeTypeHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool RuntimeMethodHandle(ref RuntimeMethodHandle x, ref RuntimeMethodHandle y)
|
||||||
|
=> x.Value == y.Value;
|
||||||
|
|
||||||
|
public static bool Enum<T>(ref T x, ref T y) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCast(x) == JitHelpers.UnsafeEnumCast(y);
|
||||||
|
|
||||||
|
public static bool LongEnum<T>(ref T x, ref T y) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCastLong(x) == JitHelpers.UnsafeEnumCastLong(y);
|
||||||
|
|
||||||
|
public static bool EquatableValueType<T>(ref T x, ref T y) where T : struct, IEquatable<T>
|
||||||
|
=> x.Equals(y);
|
||||||
|
|
||||||
|
public static bool Nullable<T>(ref T? x, ref T? y) where T : struct, IEquatable<T>
|
||||||
|
=> x.HasValue
|
||||||
|
? y.HasValue && x.Value.Equals(y.Value)
|
||||||
|
: !y.HasValue;
|
||||||
|
|
||||||
|
public static bool EquatableReferenceType<T>(ref T x, ref T y) where T : IEquatable<T>
|
||||||
|
=> x != null
|
||||||
|
? y != null && x.Equals(y)
|
||||||
|
: y == null;
|
||||||
|
|
||||||
|
public static bool Reference<T>(ref T x, ref T y) where T : class
|
||||||
|
=> x == y;
|
||||||
|
|
||||||
|
public static bool Object<T>(ref T x, ref T y)
|
||||||
|
=> x != null
|
||||||
|
? y != null && x.Equals(y)
|
||||||
|
: y == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static unsafe IntPtr MakeDelegate(Type type)
|
||||||
|
=> _equalsMethods.Where(m => !m.IsGenericMethod)
|
||||||
|
.FirstOrDefault(m
|
||||||
|
=> m.GetParameters().First().ParameterType.GetElementType() == type)
|
||||||
|
is { } specializedMethod
|
||||||
|
? specializedMethod.GetFunctionPointer()
|
||||||
|
: type.IsAssignableTo(typeof(IEquatable<>), type)
|
||||||
|
? GetMethod(
|
||||||
|
type.IsValueType
|
||||||
|
? nameof(Methods.EquatableValueType)
|
||||||
|
: nameof(Methods.EquatableReferenceType))
|
||||||
|
.MakeGenericMethod(type)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer()
|
||||||
|
: type.IsNullable(out var genericArgument)
|
||||||
|
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||||
|
? GetMethod(nameof(Methods.Nullable)).MakeGenericMethod(genericArgument)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer()
|
||||||
|
: GetMethod(
|
||||||
|
type.IsEnum
|
||||||
|
? Type.GetTypeCode(Enum.GetUnderlyingType(type))
|
||||||
|
switch
|
||||||
|
{
|
||||||
|
TypeCode.Int16
|
||||||
|
or TypeCode.SByte
|
||||||
|
or TypeCode.Byte
|
||||||
|
or TypeCode.UInt16
|
||||||
|
or TypeCode.Int32
|
||||||
|
or TypeCode.UInt32 => nameof(Methods.Enum),
|
||||||
|
TypeCode.Int64
|
||||||
|
or TypeCode.UInt64 => nameof(Methods.LongEnum),
|
||||||
|
_ => ThrowHelper.ThrowNotSupportedException<string>()
|
||||||
|
}
|
||||||
|
: nameof(Methods.Object)
|
||||||
|
).MakeGenericMethod(type)/*.CreateDelegate(typeof(EqualsDelegate<>).MakeGenericType(type)).Method*/.GetFunctionPointer();
|
||||||
|
|
||||||
|
private static MethodInfo GetMethod(string name)
|
||||||
|
=> Array.Find(_equalsMethods, m => m.Name == name);
|
||||||
|
|
||||||
|
private static MethodInfo[] _equalsMethods
|
||||||
|
= typeof(Methods)
|
||||||
|
.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m
|
||||||
|
=> m.ReturnType == typeof(bool)
|
||||||
|
&& m.GetParameters().Length == 2)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
//internal delegate bool EqualsDelegate<T>(ref T x, ref T y);
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
public static class GetHashCode<T>
|
||||||
|
{
|
||||||
|
public static readonly unsafe delegate*<T, int> Default = (delegate*<T, int>)FunctionPointers.GetHashCode.MakeDelegate(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GetHashCode
|
||||||
|
{
|
||||||
|
public static class Methods
|
||||||
|
{
|
||||||
|
public static int Byte(byte obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static int Int(int obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static int Uint(uint obj)
|
||||||
|
=> (int)obj;
|
||||||
|
|
||||||
|
public static int Ushort(ushort obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static unsafe int VoidPtr(void* obj)
|
||||||
|
=> (int)obj;
|
||||||
|
|
||||||
|
public static int Enum<T>(T obj) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCast(obj).GetHashCode();
|
||||||
|
|
||||||
|
public static int SbyteEnum<T>(T obj) where T : struct
|
||||||
|
=> ((sbyte)JitHelpers.UnsafeEnumCast(obj)).GetHashCode();
|
||||||
|
|
||||||
|
public static int ShortEnum<T>(T obj) where T : struct
|
||||||
|
=> ((short)JitHelpers.UnsafeEnumCast(obj)).GetHashCode();
|
||||||
|
|
||||||
|
public static int LongEnum<T>(T obj) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCastLong(obj).GetHashCode();
|
||||||
|
|
||||||
|
public static int ValueType<T>(T obj) where T : struct
|
||||||
|
=> obj.GetHashCode();
|
||||||
|
|
||||||
|
public static int Nullable<T>(T? obj) where T : struct
|
||||||
|
=> obj.GetHashCode();
|
||||||
|
|
||||||
|
public static int Reference<T>(T obj) where T : class
|
||||||
|
=> RuntimeHelpers.GetHashCode(obj);
|
||||||
|
|
||||||
|
public static int Object<T>(T obj)
|
||||||
|
=> obj?.GetHashCode() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static unsafe IntPtr MakeDelegate(Type type)
|
||||||
|
=> _getHashCodeMethods.Where(m => !m.IsGenericMethod)
|
||||||
|
.FirstOrDefault(m
|
||||||
|
=> m.GetParameters().First().ParameterType == type)
|
||||||
|
is { } specializedMethod
|
||||||
|
? specializedMethod.GetFunctionPointer()
|
||||||
|
: type.IsNullable(out var genericArgument)
|
||||||
|
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||||
|
? GetMethod(nameof(Methods.Nullable)).MakeGenericMethod(genericArgument).GetFunctionPointer()
|
||||||
|
: GetMethod(
|
||||||
|
type.IsEnum
|
||||||
|
? Type.GetTypeCode(Enum.GetUnderlyingType(type))
|
||||||
|
switch
|
||||||
|
{
|
||||||
|
TypeCode.Int16 => nameof(Methods.ShortEnum),
|
||||||
|
TypeCode.SByte => nameof(Methods.SbyteEnum),
|
||||||
|
TypeCode.Byte
|
||||||
|
or TypeCode.UInt16
|
||||||
|
or TypeCode.Int32
|
||||||
|
or TypeCode.UInt32 => nameof(Methods.Enum),
|
||||||
|
TypeCode.Int64
|
||||||
|
or TypeCode.UInt64 => nameof(Methods.LongEnum),
|
||||||
|
_ => ThrowHelper.ThrowNotSupportedException<string>()
|
||||||
|
}
|
||||||
|
: type.IsValueType
|
||||||
|
? nameof(Methods.ValueType)
|
||||||
|
: nameof(Methods.Object)
|
||||||
|
).MakeGenericMethod(type).GetFunctionPointer();
|
||||||
|
|
||||||
|
private static MethodInfo GetMethod(string name)
|
||||||
|
=> Array.Find(_getHashCodeMethods, m => m.Name == name);
|
||||||
|
|
||||||
|
private static MethodInfo[] _getHashCodeMethods
|
||||||
|
= typeof(Methods)
|
||||||
|
.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m
|
||||||
|
=> m.ReturnType == typeof(int)
|
||||||
|
&& m.GetParameters().Length == 1)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe delegate*<V, int> Cast<T,V>(delegate*<T, int> @delegate)
|
||||||
|
=> (delegate*<V, int>)@delegate;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static unsafe delegate*<T, int> CastVoid<T>(delegate*<void*, int> @delegate)
|
||||||
|
=> (delegate*<T, int>)@delegate;
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib.FunctionPointers;
|
||||||
|
public static class GetHashCodeByRef<T>
|
||||||
|
{
|
||||||
|
public static readonly unsafe delegate*<ref T, int> Default = (delegate*<ref T, int>)GetHashCodeByRef.MakeDelegate(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GetHashCodeByRef
|
||||||
|
{
|
||||||
|
public static class Methods
|
||||||
|
{
|
||||||
|
public static int Byte(ref byte obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static int Int(ref int obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static int Uint(ref uint obj)
|
||||||
|
=> (int)obj;
|
||||||
|
|
||||||
|
public static int Ushort(ref ushort obj)
|
||||||
|
=> obj;
|
||||||
|
|
||||||
|
public static unsafe int VoidPtr(ref void* obj)
|
||||||
|
=> (int)obj;
|
||||||
|
|
||||||
|
public static int Enum<T>(ref T obj) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCast(obj).GetHashCode();
|
||||||
|
|
||||||
|
public static int SbyteEnum<T>(ref T obj) where T : struct
|
||||||
|
=> ((sbyte)JitHelpers.UnsafeEnumCast(obj)).GetHashCode();
|
||||||
|
|
||||||
|
public static int ShortEnum<T>(ref T obj) where T : struct
|
||||||
|
=> ((short)JitHelpers.UnsafeEnumCast(obj)).GetHashCode();
|
||||||
|
|
||||||
|
public static int LongEnum<T>(ref T obj) where T : struct
|
||||||
|
=> JitHelpers.UnsafeEnumCastLong(obj).GetHashCode();
|
||||||
|
|
||||||
|
public static int ValueType<T>(ref T obj) where T : struct
|
||||||
|
=> obj.GetHashCode();
|
||||||
|
|
||||||
|
public static int Nullable<T>(ref T? obj) where T : struct
|
||||||
|
=> obj.GetHashCode();
|
||||||
|
|
||||||
|
public static int Reference<T>(ref T obj) where T : class
|
||||||
|
=> RuntimeHelpers.GetHashCode(obj);
|
||||||
|
|
||||||
|
public static int Object<T>(ref T obj)
|
||||||
|
=> obj?.GetHashCode() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static unsafe IntPtr MakeDelegate(Type type)
|
||||||
|
=> _getHashCodeMethods.Where(m => !m.IsGenericMethod)
|
||||||
|
.FirstOrDefault(m
|
||||||
|
=> m.GetParameters().First().ParameterType.GetElementType() == type)
|
||||||
|
is { } specializedMethod
|
||||||
|
? specializedMethod.GetFunctionPointer()
|
||||||
|
: type.IsNullable(out var genericArgument)
|
||||||
|
&& genericArgument.IsAssignableTo(typeof(IEquatable<>), genericArgument)
|
||||||
|
? GetMethod(nameof(Methods.Nullable)).MakeGenericMethod(genericArgument).GetFunctionPointer()
|
||||||
|
: GetMethod(
|
||||||
|
type.IsEnum
|
||||||
|
? Type.GetTypeCode(Enum.GetUnderlyingType(type))
|
||||||
|
switch
|
||||||
|
{
|
||||||
|
TypeCode.Int16 => nameof(Methods.ShortEnum),
|
||||||
|
TypeCode.SByte => nameof(Methods.SbyteEnum),
|
||||||
|
TypeCode.Byte
|
||||||
|
or TypeCode.UInt16
|
||||||
|
or TypeCode.Int32
|
||||||
|
or TypeCode.UInt32 => nameof(Methods.Enum),
|
||||||
|
TypeCode.Int64
|
||||||
|
or TypeCode.UInt64 => nameof(Methods.LongEnum),
|
||||||
|
_ => ThrowHelper.ThrowNotSupportedException<string>()
|
||||||
|
}
|
||||||
|
: type.IsValueType
|
||||||
|
? nameof(Methods.ValueType)
|
||||||
|
: nameof(Methods.Object)
|
||||||
|
).MakeGenericMethod(type).GetFunctionPointer();
|
||||||
|
|
||||||
|
private static MethodInfo GetMethod(string name)
|
||||||
|
=> Array.Find(_getHashCodeMethods, m => m.Name == name);
|
||||||
|
|
||||||
|
private static MethodInfo[] _getHashCodeMethods
|
||||||
|
= typeof(Methods)
|
||||||
|
.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m
|
||||||
|
=> m.ReturnType == typeof(int)
|
||||||
|
&& m.GetParameters().Length == 1)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
/*namespace FisheryLib;
|
||||||
|
public static class HarmonyPatchExtensions
|
||||||
|
{
|
||||||
|
/// <summary>Creates patches by manually specifying the methods</summary>
|
||||||
|
/// <param name="original">The original method/constructor</param>
|
||||||
|
/// <param name="prefix">An optional prefix method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="postfix">An optional postfix method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="infix">An optional infix method wrapped in a <see cref="InfixMethod"/> object</param>
|
||||||
|
/// <param name="transpiler">An optional transpiler method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <param name="finalizer">An optional finalizer method wrapped in a <see cref="HarmonyMethod"/> object</param>
|
||||||
|
/// <returns>The replacement method that was created to patch the original method</returns>
|
||||||
|
public static MethodInfo Patch(this Harmony harmony, MethodBase original, HarmonyMethod? prefix = null, HarmonyMethod? postfix = null, InfixMethod? infix = null, HarmonyMethod? transpiler = null, HarmonyMethod? finalizer = null)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(harmony, nameof(harmony));
|
||||||
|
Guard.IsNotNull(original, nameof(original));
|
||||||
|
|
||||||
|
var patchProcessor = harmony.CreateProcessor(original);
|
||||||
|
patchProcessor.AddPrefix(prefix);
|
||||||
|
patchProcessor.AddPostfix(postfix);
|
||||||
|
patchProcessor.AddTranspiler(infix);
|
||||||
|
patchProcessor.AddTranspiler(transpiler);
|
||||||
|
patchProcessor.AddFinalizer(finalizer);
|
||||||
|
return patchProcessor.Patch();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// 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 HashCode
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe int Get<T>([AllowNull] T obj)
|
||||||
|
=> FunctionPointers.GetHashCode<T>.Default(obj!);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe int Get<T>([AllowNull] ref T obj)
|
||||||
|
=> FunctionPointers.GetHashCodeByRef<T>.Default(ref obj!);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine<T_first, T_second>(T_first first, T_second second)
|
||||||
|
//where T_first : notnull where T_second : notnull
|
||||||
|
=> Combine(Get(first), Get(second));
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine(int first, int second)
|
||||||
|
=> unchecked((1009 * 9176) + first).CombineWith(second); //https://stackoverflow.com/questions/1646807/quick-and-simple-hash-code-combinations/34006336#34006336
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine<T_first, T_second, T_third>(T_first first, T_second second, T_third third)
|
||||||
|
//where T_first : notnull where T_second : notnull where T_third : notnull
|
||||||
|
=> Combine(first, second).CombineWith(third);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine(int first, int second, int third)
|
||||||
|
=> Combine(first, second).CombineWith(third);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine<T_first, T_second, T_third, T_fourth>(T_first first, T_second second, T_third third, T_fourth fourth)
|
||||||
|
//where T_first : notnull where T_second : notnull where T_third : notnull where T_fourth : notnull
|
||||||
|
=> Combine(first, second, third).CombineWith(fourth);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Combine(int first, int second, int third, int fourth)
|
||||||
|
=> Combine(first, second, third).CombineWith(fourth);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int CombineWith(this int first, int second)
|
||||||
|
=> unchecked((first * 9176) + second);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static int CombineWith<T>(this int first, T second)
|
||||||
|
//where T : notnull
|
||||||
|
=> unchecked((first * 9176) + Get(second));
|
||||||
|
}
|
||||||
@@ -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.Linq;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
public class InfixMethod : HarmonyMethod
|
||||||
|
{
|
||||||
|
public InfixMethod(MethodInfo method, InfixTarget target)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(method, nameof(method));
|
||||||
|
|
||||||
|
ImportMethod(method, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImportMethod(MethodInfo theMethod, InfixTarget target)
|
||||||
|
{
|
||||||
|
method = MakeInfixMethod(theMethod, target).Method;
|
||||||
|
if (method is not null
|
||||||
|
&& HarmonyMethodExtensions.GetFromMethod(method) is { } fromMethod)
|
||||||
|
{
|
||||||
|
Merge(fromMethod).CopyTo(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static InfixDelegate MakeInfixMethod(MethodInfo theMethod, InfixTarget target)
|
||||||
|
=> (codes, original)
|
||||||
|
=> target.Mode switch
|
||||||
|
{
|
||||||
|
InfixTargetMode.After => codes.InsertAfter(target.Predicate, GetInfixInstructions(original, theMethod)),
|
||||||
|
InfixTargetMode.Replace => codes.Replace(target.Predicate, code => FishTranspiler.Call(theMethod)), // <-- this one is different
|
||||||
|
InfixTargetMode.Before => codes.InsertBefore(target.Predicate, GetInfixInstructions(original, theMethod)),
|
||||||
|
_ => throw new($"Invalid InfixTargetMode for {theMethod.FullDescription()}")
|
||||||
|
};
|
||||||
|
|
||||||
|
private static IEnumerable<CodeInstruction> GetInfixInstructions(MethodBase original, MethodInfo infixMethod)
|
||||||
|
{
|
||||||
|
var originalParameters = original.GetParameters();
|
||||||
|
foreach (var argument in infixMethod.GetParameters())
|
||||||
|
{
|
||||||
|
var argumentName = argument.Name;
|
||||||
|
var argumentType = argument.ParameterType;
|
||||||
|
|
||||||
|
if (argumentName == "__instance")
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.This;
|
||||||
|
}
|
||||||
|
else if (argumentName == "__args")
|
||||||
|
{
|
||||||
|
foreach (var code in GetArgsArray(originalParameters))
|
||||||
|
yield return code;
|
||||||
|
}
|
||||||
|
else if (argumentName == "__originalMethod")
|
||||||
|
{
|
||||||
|
foreach (var code in GetOriginalMethod(original))
|
||||||
|
yield return code;
|
||||||
|
}
|
||||||
|
else if (argumentName is "__result")
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Infixes do not support __result.");
|
||||||
|
}
|
||||||
|
else if (argumentName is "__state")
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Infixes do not support __state.");
|
||||||
|
}
|
||||||
|
//argument
|
||||||
|
else if (original.GetParameters().Any(parm => parm.Name == argumentName))
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Argument(original, argumentName);
|
||||||
|
}
|
||||||
|
//___field
|
||||||
|
else if (argumentName.StartsWith("___"))
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Field(argumentType, argumentName.Remove(0, 3));
|
||||||
|
}
|
||||||
|
//vars
|
||||||
|
else if (argumentName.StartsWith("__"))
|
||||||
|
{
|
||||||
|
yield return GetVarInstruction(original, argumentName, argumentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return FishTranspiler.Call(infixMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<CodeInstruction> GetOriginalMethod(MethodBase original)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(original, nameof(original));
|
||||||
|
|
||||||
|
if (original is MethodInfo or ConstructorInfo)
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Token(original);
|
||||||
|
|
||||||
|
if (original.ReflectedType is { IsGenericType: true } type)
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Token(type);
|
||||||
|
yield return FishTranspiler.Call<Func<RuntimeMethodHandle, RuntimeTypeHandle, MethodBase>>(MethodBase.GetMethodFromHandle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Call<Func<RuntimeMethodHandle, MethodBase>>(MethodBase.GetMethodFromHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yield return FishTranspiler.Null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<CodeInstruction> GetArgsArray(ParameterInfo[] originalParameters)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(originalParameters, nameof(originalParameters));
|
||||||
|
|
||||||
|
yield return FishTranspiler.Constant(originalParameters.Length);
|
||||||
|
yield return FishTranspiler.New<object[]>();
|
||||||
|
|
||||||
|
for (var i = 0; i < originalParameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameter = originalParameters[i];
|
||||||
|
|
||||||
|
yield return FishTranspiler.Duplicate;
|
||||||
|
yield return FishTranspiler.Constant(i);
|
||||||
|
yield return FishTranspiler.Argument(parameter);
|
||||||
|
|
||||||
|
var parameterType = parameter.ParameterType;
|
||||||
|
if (parameterType.IsByRef)
|
||||||
|
{
|
||||||
|
parameterType = parameterType.GetElementType();
|
||||||
|
yield return FishTranspiler.LoadByRef(parameterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterType.IsValueType)
|
||||||
|
yield return FishTranspiler.Box(parameterType);
|
||||||
|
|
||||||
|
yield return FishTranspiler.StoreElement<object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodeInstruction GetVarInstruction(MethodBase original, string argumentName, Type argumentType)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(original, nameof(original));
|
||||||
|
Guard.IsNotNullOrEmpty(argumentName, nameof(argumentName));
|
||||||
|
Guard.IsNotNull(argumentType, nameof(argumentType));
|
||||||
|
|
||||||
|
//__var
|
||||||
|
return argumentName == "__var"
|
||||||
|
? FishTranspiler.FirstLocalVariable(original, argumentType)
|
||||||
|
|
||||||
|
//__var#
|
||||||
|
: argumentName.Contains("__var") && int.TryParse(argumentName.Trim('_', 'v', 'a', 'r'), out var index)
|
||||||
|
? FishTranspiler.LocalVariable(index)
|
||||||
|
|
||||||
|
//__*#
|
||||||
|
: int.TryParse(new(argumentName.Where(char.IsDigit).ToArray()), out index)
|
||||||
|
? FishTranspiler.MatchingLocalVariables(original, loc => loc.LocalType == argumentType).ElementAt(index)
|
||||||
|
|
||||||
|
//__*
|
||||||
|
: FishTranspiler.FirstLocalVariable(original, argumentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static HarmonyMethod Merge(List<HarmonyMethod> attributes)
|
||||||
|
//{
|
||||||
|
// var harmonyMethod = new HarmonyMethod();
|
||||||
|
|
||||||
|
// if (attributes == null)
|
||||||
|
// return harmonyMethod;
|
||||||
|
|
||||||
|
// var resultTrv = Traverse.Create(harmonyMethod);
|
||||||
|
// attributes.ForEach((HarmonyMethod attribute) =>
|
||||||
|
// {
|
||||||
|
// var trv = Traverse.Create(attribute);
|
||||||
|
// HarmonyFields().ForEach(delegate (string f)
|
||||||
|
// {
|
||||||
|
// var value = trv.Field(f).GetValue();
|
||||||
|
// if (value != null && (f != "priority" || (int)value != -1))
|
||||||
|
// {
|
||||||
|
// HarmonyMethodExtensions.SetValue(resultTrv, f, value);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// return harmonyMethod;
|
||||||
|
//}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// hide overridden HarmonyMethod ctors as they're insufficient for infixes
|
||||||
|
/// </summary>
|
||||||
|
#pragma warning disable IDE0051, IDE0060
|
||||||
|
private InfixMethod(MethodInfo method) { }
|
||||||
|
private InfixMethod(MethodInfo method, int priority, string[] before, string[] after, bool? debug) { }
|
||||||
|
private InfixMethod(Type methodType, string methodName, Type[] argumentTypes) { }
|
||||||
|
#pragma warning restore IDE0051, IDE0060
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate IEnumerable<CodeInstruction> InfixDelegate(IEnumerable<CodeInstruction> codes, MethodBase original);
|
||||||
|
|
||||||
|
public struct InfixTarget
|
||||||
|
{
|
||||||
|
public Predicate<CodeInstruction> Predicate { get; }
|
||||||
|
public InfixTargetMode Mode { get; }
|
||||||
|
|
||||||
|
public InfixTarget(MethodInfo calledMethod, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(calledMethod, nameof(calledMethod));
|
||||||
|
|
||||||
|
Predicate = code => code.Calls(calledMethod);
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfixTarget(FieldInfo loadedField, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(loadedField, nameof(loadedField));
|
||||||
|
|
||||||
|
Predicate = code => code.LoadsField(loadedField);
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfixTarget(long constantValue, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Predicate = code => code.LoadsConstant(constantValue);
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfixTarget(double constantValue, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Predicate = code => code.LoadsConstant(constantValue);
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfixTarget(Enum constantValue, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Predicate = code => code.LoadsConstant(constantValue);
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfixTarget(Predicate<CodeInstruction> predicate, InfixTargetMode targetMode)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(predicate, nameof(predicate));
|
||||||
|
|
||||||
|
Predicate = predicate;
|
||||||
|
Mode = targetMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InfixTargetMode
|
||||||
|
{
|
||||||
|
After,
|
||||||
|
Replace,
|
||||||
|
Before
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class InfixAttribute : Attribute
|
||||||
|
{
|
||||||
|
public InfixTarget InfixTarget { get; }
|
||||||
|
|
||||||
|
public InfixAttribute(InfixTarget target) => InfixTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InfixBeforeAttribute : InfixAttribute
|
||||||
|
{
|
||||||
|
public InfixBeforeAttribute(MethodInfo methodCall)
|
||||||
|
: base(new(NotNull(methodCall), InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixBeforeAttribute(FieldInfo fieldToLoad)
|
||||||
|
: base(new(NotNull(fieldToLoad), InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixBeforeAttribute(long constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixBeforeAttribute(double constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixBeforeAttribute(Enum constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixBeforeAttribute(Predicate<CodeInstruction> predicate)
|
||||||
|
: base(new(NotNull(predicate), InfixTargetMode.Before))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InfixAfterAttribute : InfixAttribute
|
||||||
|
{
|
||||||
|
public InfixAfterAttribute(MethodInfo methodCall)
|
||||||
|
: base(new(NotNull(methodCall), InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixAfterAttribute(FieldInfo fieldToLoad)
|
||||||
|
: base(new(NotNull(fieldToLoad), InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixAfterAttribute(long constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixAfterAttribute(double constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixAfterAttribute(Enum constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixAfterAttribute(Predicate<CodeInstruction> predicate)
|
||||||
|
: base(new(NotNull(predicate), InfixTargetMode.After))
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InfixReplaceAttribute : InfixAttribute
|
||||||
|
{
|
||||||
|
public InfixReplaceAttribute(MethodInfo methodCall)
|
||||||
|
: base(new(NotNull(methodCall), InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixReplaceAttribute(FieldInfo fieldToLoad)
|
||||||
|
: base(new(NotNull(fieldToLoad), InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixReplaceAttribute(long constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixReplaceAttribute(double constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixReplaceAttribute(Enum constantValue)
|
||||||
|
: base(new(constantValue, InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public InfixReplaceAttribute(Predicate<CodeInstruction> predicate)
|
||||||
|
: base(new(NotNull(predicate), InfixTargetMode.Replace))
|
||||||
|
{ }
|
||||||
|
}*/
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
|
||||||
|
public static class Log
|
||||||
|
{
|
||||||
|
public static void Message(string message) => _message(message);
|
||||||
|
public static void Warning(string message) => _warning(message);
|
||||||
|
public static void Error(string message) => _error(message);
|
||||||
|
|
||||||
|
public static class Config
|
||||||
|
{
|
||||||
|
public static Action<string> Message { set => _message = value; }
|
||||||
|
public static Action<string> Warning { set => _warning = value; }
|
||||||
|
public static Action<string> Error { set => _error = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Action<string> _message = Verse.Log.Message;
|
||||||
|
private static Action<string> _warning = Verse.Log.Warning;
|
||||||
|
private static Action<string> _error = Verse.Log.Error;
|
||||||
|
}
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
|
||||||
|
/// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal static class MemoryMarshal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
|
||||||
|
/// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Thrown when <typeparamref name="T"/> contains pointers.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.OverflowException">
|
||||||
|
/// Thrown if the Length property of the new Span would exceed int.MaxValue.
|
||||||
|
/// </exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe Span<byte> AsBytes<T>(Span<T> span)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
|
||||||
|
return new Span<byte>(
|
||||||
|
Unsafe.AsPointer(ref GetReference(span)),
|
||||||
|
checked(span.Length * Unsafe.SizeOf<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
|
||||||
|
/// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Thrown when <typeparamref name="T"/> contains pointers.
|
||||||
|
/// </exception>
|
||||||
|
/// <exception cref="System.OverflowException">
|
||||||
|
/// Thrown if the Length property of the new Span would exceed int.MaxValue.
|
||||||
|
/// </exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe ReadOnlySpan<byte> AsBytes<T>(ReadOnlySpan<T> span)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
|
||||||
|
return new ReadOnlySpan<byte>(
|
||||||
|
Unsafe.AsPointer(ref GetReference(span)),
|
||||||
|
checked(span.Length * Unsafe.SizeOf<T>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
|
||||||
|
/// <param name="memory">The <see cref="ReadOnlyMemory{T}"/>.</param>
|
||||||
|
/// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
|
||||||
|
/// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
|
||||||
|
/// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
|
||||||
|
/// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
|
||||||
|
Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
|
||||||
|
/// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T GetReference<T>(Span<T> span) => ref span.DangerousGetPinnableReference();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
|
||||||
|
/// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span.DangerousGetPinnableReference();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
|
||||||
|
/// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span.DangerousGetPinnableReference() : ref Unsafe.AsRef<T>((void*)1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
|
||||||
|
/// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span.DangerousGetPinnableReference() : ref Unsafe.AsRef<T>((void*)1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
|
||||||
|
/// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
|
||||||
|
/// </exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
|
||||||
|
where TFrom : struct
|
||||||
|
where TTo : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
|
||||||
|
|
||||||
|
// Use unsigned integers - unsigned division by constant (especially by power of 2)
|
||||||
|
// and checked casts are faster and smaller.
|
||||||
|
var fromSize = (uint)Unsafe.SizeOf<TFrom>();
|
||||||
|
var toSize = (uint)Unsafe.SizeOf<TTo>();
|
||||||
|
var fromLength = (uint)span.Length;
|
||||||
|
int toLength;
|
||||||
|
if (fromSize == toSize)
|
||||||
|
{
|
||||||
|
// Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
|
||||||
|
// should be optimized to just `length` but the JIT doesn't do that today.
|
||||||
|
toLength = (int)fromLength;
|
||||||
|
}
|
||||||
|
else if (fromSize == 1)
|
||||||
|
{
|
||||||
|
// Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
|
||||||
|
// becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
|
||||||
|
// and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
|
||||||
|
// the JIT can't eliminate long multiply by 1.
|
||||||
|
toLength = (int)(fromLength / toSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ensure that casts are done in such a way that the JIT is able to "see"
|
||||||
|
// the uint->ulong casts and the multiply together so that on 32 bit targets
|
||||||
|
// 32x32to64 multiplication is used.
|
||||||
|
var toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
|
||||||
|
toLength = checked((int)toLengthUInt64);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return new Span<TTo>(
|
||||||
|
Unsafe.AsPointer(ref span.DangerousGetPinnableReference()),
|
||||||
|
toLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
|
||||||
|
/// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
|
||||||
|
/// <exception cref="System.ArgumentException">
|
||||||
|
/// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
|
||||||
|
/// </exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
|
||||||
|
where TFrom : struct
|
||||||
|
where TTo : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
|
||||||
|
|
||||||
|
// Use unsigned integers - unsigned division by constant (especially by power of 2)
|
||||||
|
// and checked casts are faster and smaller.
|
||||||
|
var fromSize = (uint)Unsafe.SizeOf<TFrom>();
|
||||||
|
var toSize = (uint)Unsafe.SizeOf<TTo>();
|
||||||
|
var fromLength = (uint)span.Length;
|
||||||
|
int toLength;
|
||||||
|
if (fromSize == toSize)
|
||||||
|
{
|
||||||
|
// Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
|
||||||
|
// should be optimized to just `length` but the JIT doesn't do that today.
|
||||||
|
toLength = (int)fromLength;
|
||||||
|
}
|
||||||
|
else if (fromSize == 1)
|
||||||
|
{
|
||||||
|
// Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
|
||||||
|
// becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
|
||||||
|
// and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
|
||||||
|
// the JIT can't eliminate long multiply by 1.
|
||||||
|
toLength = (int)(fromLength / toSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ensure that casts are done in such a way that the JIT is able to "see"
|
||||||
|
// the uint->ulong casts and the multiply together so that on 32 bit targets
|
||||||
|
// 32x32to64 multiplication is used.
|
||||||
|
var toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
|
||||||
|
toLength = checked((int)toLengthUInt64);
|
||||||
|
}
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return new ReadOnlySpan<TTo>(
|
||||||
|
Unsafe.AsPointer(ref GetReference(span)),
|
||||||
|
toLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new span over a portion of a regular managed object. This can be useful
|
||||||
|
/// if part of a managed object represents a "fixed array." This is dangerous because the
|
||||||
|
/// <paramref name="length"/> is not checked.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reference">A reference to data.</param>
|
||||||
|
/// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
|
||||||
|
/// <returns>A span representing the specified reference and length.</returns>
|
||||||
|
/// <remarks>The lifetime of the returned span will not be validated for safety by span-aware languages.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe Span<T> CreateSpan<T>(ref T reference, int length) => new(Unsafe.AsPointer(ref reference), length);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new read-only span over a portion of a regular managed object. This can be useful
|
||||||
|
/// if part of a managed object represents a "fixed array." This is dangerous because the
|
||||||
|
/// <paramref name="length"/> is not checked.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reference">A reference to data.</param>
|
||||||
|
/// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
|
||||||
|
/// <returns>A read-only span representing the specified reference and length.</returns>
|
||||||
|
/// <remarks>The lifetime of the returned span will not be validated for safety by span-aware languages.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) => new(Unsafe.AsPointer(ref reference), length);
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>Creates a new read-only span for a null-terminated string.</summary>
|
||||||
|
/// <param name="value">The pointer to the null-terminated string of characters.</param>
|
||||||
|
/// <returns>A read-only span representing the specified null-terminated string, or an empty span if the pointer is null.</returns>
|
||||||
|
/// <remarks>The returned span does not include the null terminator.</remarks>
|
||||||
|
/// <exception cref="ArgumentException">The string is longer than <see cref="int.MaxValue"/>.</exception>
|
||||||
|
public static unsafe ReadOnlySpan<char> CreateReadOnlySpanFromNullTerminated(char* value) =>
|
||||||
|
value != null ? new ReadOnlySpan<char>(value, string.wcslen(value)) :
|
||||||
|
default;
|
||||||
|
|
||||||
|
/// <summary>Creates a new read-only span for a null-terminated UTF8 string.</summary>
|
||||||
|
/// <param name="value">The pointer to the null-terminated string of bytes.</param>
|
||||||
|
/// <returns>A read-only span representing the specified null-terminated string, or an empty span if the pointer is null.</returns>
|
||||||
|
/// <remarks>The returned span does not include the null terminator, nor does it validate the well-formedness of the UTF8 data.</remarks>
|
||||||
|
/// <exception cref="ArgumentException">The string is longer than <see cref="int.MaxValue"/>.</exception>
|
||||||
|
public static unsafe ReadOnlySpan<byte> CreateReadOnlySpanFromNullTerminated(byte* value) =>
|
||||||
|
value != null ? new ReadOnlySpan<byte>(value, string.strlen(value)) :
|
||||||
|
default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an array segment from the underlying memory.
|
||||||
|
/// If unable to get the array segment, return false with a default array segment.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGetArray<T>(ReadOnlyMemory<T> memory, out ArraySegment<T> segment)
|
||||||
|
{
|
||||||
|
object? obj = memory.GetObjectStartLength(out int index, out int length);
|
||||||
|
|
||||||
|
// As an optimization, we skip the "is string?" check below if typeof(T) is not char,
|
||||||
|
// as Memory<T> / ROM<T> can't possibly contain a string instance in this case.
|
||||||
|
|
||||||
|
if (obj != null && !(
|
||||||
|
(typeof(T) == typeof(char) && obj.GetType() == typeof(string))
|
||||||
|
))
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.ObjectHasComponentSize(obj))
|
||||||
|
{
|
||||||
|
// The object has a component size, which means it's variable-length, but we already
|
||||||
|
// checked above that it's not a string. The only remaining option is that it's a T[]
|
||||||
|
// or a U[] which is blittable to a T[] (e.g., int[] and uint[]).
|
||||||
|
|
||||||
|
// The array may be prepinned, so remove the high bit from the start index in the line below.
|
||||||
|
// The ArraySegment<T> ctor will perform bounds checking on index & length.
|
||||||
|
|
||||||
|
segment = new ArraySegment<T>(Unsafe.As<T[]>(obj), index & ReadOnlyMemory<T>.RemoveFlagsBitMask, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The object isn't null, and it's not variable-length, so the only remaining option
|
||||||
|
// is MemoryManager<T>. The ArraySegment<T> ctor will perform bounds checking on index & length.
|
||||||
|
|
||||||
|
Debug.Assert(obj is MemoryManager<T>);
|
||||||
|
if (Unsafe.As<MemoryManager<T>>(obj).TryGetArray(out ArraySegment<T> tempArraySegment))
|
||||||
|
{
|
||||||
|
segment = new ArraySegment<T>(tempArraySegment.Array!, tempArraySegment.Offset + index, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got to this point, the object is null, or it's a string, or it's a MemoryManager<T>
|
||||||
|
// which isn't backed by an array. We'll quickly homogenize all zero-length Memory<T> instances
|
||||||
|
// to an empty array for the purposes of reporting back to our caller.
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
segment = ArraySegment<T>.Empty;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, there's *some* data, but it's not convertible to T[].
|
||||||
|
|
||||||
|
segment = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="MemoryManager{T}"/> from the underlying read-only memory.
|
||||||
|
/// If unable to get the <typeparamref name="TManager"/> type, returns false.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
|
||||||
|
/// <typeparam name="TManager">The type of <see cref="MemoryManager{T}"/> to try and retrieve.</typeparam>
|
||||||
|
/// <param name="memory">The memory to get the manager for.</param>
|
||||||
|
/// <param name="manager">The returned manager of the <see cref="ReadOnlyMemory{T}"/>.</param>
|
||||||
|
/// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
|
||||||
|
public static bool TryGetMemoryManager<T, TManager>(ReadOnlyMemory<T> memory, [NotNullWhen(true)] out TManager? manager)
|
||||||
|
where TManager : MemoryManager<T>
|
||||||
|
{
|
||||||
|
TManager? localManager; // Use register for null comparison rather than byref
|
||||||
|
manager = localManager = memory.GetObjectStartLength(out _, out _) as TManager;
|
||||||
|
#pragma warning disable 8762 // "Parameter 'manager' may not have a null value when exiting with 'true'."
|
||||||
|
return localManager != null;
|
||||||
|
#pragma warning restore 8762
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="MemoryManager{T}"/> and <paramref name="start" />, <paramref name="length" /> from the underlying read-only memory.
|
||||||
|
/// If unable to get the <typeparamref name="TManager"/> type, returns false.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
|
||||||
|
/// <typeparam name="TManager">The type of <see cref="MemoryManager{T}"/> to try and retrieve.</typeparam>
|
||||||
|
/// <param name="memory">The memory to get the manager for.</param>
|
||||||
|
/// <param name="manager">The returned manager of the <see cref="ReadOnlyMemory{T}"/>.</param>
|
||||||
|
/// <param name="start">The offset from the start of the <paramref name="manager" /> that the <paramref name="memory" /> represents.</param>
|
||||||
|
/// <param name="length">The length of the <paramref name="manager" /> that the <paramref name="memory" /> represents.</param>
|
||||||
|
/// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
|
||||||
|
public static bool TryGetMemoryManager<T, TManager>(ReadOnlyMemory<T> memory, [NotNullWhen(true)] out TManager? manager, out int start, out int length)
|
||||||
|
where TManager : MemoryManager<T>
|
||||||
|
{
|
||||||
|
TManager? localManager; // Use register for null comparison rather than byref
|
||||||
|
manager = localManager = memory.GetObjectStartLength(out start, out length) as TManager;
|
||||||
|
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
|
||||||
|
if (localManager == null)
|
||||||
|
{
|
||||||
|
start = default;
|
||||||
|
length = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#pragma warning disable 8762 // "Parameter 'manager' may not have a null value when exiting with 'true'."
|
||||||
|
return true;
|
||||||
|
#pragma warning restore 8762
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /> to allow
|
||||||
|
/// the <paramref name="memory" /> to be used in existing APIs that take an <see cref="IEnumerable{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
|
||||||
|
/// <param name="memory">The ReadOnlyMemory to view as an <see cref="IEnumerable{T}"/></param>
|
||||||
|
/// <returns>An <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /></returns>
|
||||||
|
public static IEnumerable<T> ToEnumerable<T>(ReadOnlyMemory<T> memory)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < memory.Length; i++)
|
||||||
|
yield return memory.Span[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
|
||||||
|
/// <param name="memory">The memory that may be wrapping a <see cref="string"/> object.</param>
|
||||||
|
/// <param name="text">The string.</param>
|
||||||
|
/// <param name="start">The starting location in <paramref name="text"/>.</param>
|
||||||
|
/// <param name="length">The number of items in <paramref name="text"/>.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool TryGetString(ReadOnlyMemory<char> memory, [NotNullWhen(true)] out string? text, out int start, out int length)
|
||||||
|
{
|
||||||
|
if (memory.GetObjectStartLength(out int offset, out int count) is string s)
|
||||||
|
{
|
||||||
|
Debug.Assert(offset >= 0);
|
||||||
|
Debug.Assert(count >= 0);
|
||||||
|
text = s;
|
||||||
|
start = offset;
|
||||||
|
length = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = null;
|
||||||
|
start = 0;
|
||||||
|
length = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a structure of type T out of a read-only span of bytes.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T Read<T>(ReadOnlySpan<byte> source)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if (Unsafe.SizeOf<T>() > source.Length)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
return Unsafe.ReadUnaligned<T>(ref GetReference(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a structure of type T out of a span of bytes.
|
||||||
|
/// <returns>If the span is too small to contain the type T, return false.</returns>
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool TryRead<T>(ReadOnlySpan<byte> source, out T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if (Unsafe.SizeOf<T>() > (uint)source.Length)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = Unsafe.ReadUnaligned<T>(ref GetReference(source));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a structure of type T into a span of bytes.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Write<T>(Span<byte> destination, ref T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if ((uint)Unsafe.SizeOf<T>() > (uint)destination.Length)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
Unsafe.WriteUnaligned<T>(ref GetReference(destination), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a structure of type T into a span of bytes.
|
||||||
|
/// <returns>If the span is too small to contain the type T, return false.</returns>
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool TryWrite<T>(Span<byte> destination, ref T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if (Unsafe.SizeOf<T>() > (uint)destination.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Unsafe.WriteUnaligned(ref GetReference(destination), value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Re-interprets a span of bytes as a reference to structure of type T.
|
||||||
|
/// The type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T AsRef<T>(Span<byte> span)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if (Unsafe.SizeOf<T>() > (uint)span.Length)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
return ref Unsafe.As<byte, T>(ref GetReference(span));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Re-interprets a span of bytes as a reference to structure of type T.
|
||||||
|
/// The type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref readonly T AsRef<T>(ReadOnlySpan<byte> span)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||||
|
{
|
||||||
|
ThrowInvalidTypeWithPointersNotSupported(typeof(T));
|
||||||
|
}
|
||||||
|
if (Unsafe.SizeOf<T>() > (uint)span.Length)
|
||||||
|
{
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
return ref Unsafe.As<byte, T>(ref GetReference(span));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new memory over the portion of the pre-pinned target array beginning
|
||||||
|
/// at 'start' index and ending at 'end' index (exclusive).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">The pre-pinned target array.</param>
|
||||||
|
/// <param name="start">The index at which to begin the memory.</param>
|
||||||
|
/// <param name="length">The number of items in the memory.</param>
|
||||||
|
/// <remarks>This method should only be called on an array that is already pinned and
|
||||||
|
/// that array should not be unpinned while the returned Memory<typeparamref name="T"/> is still in use.
|
||||||
|
/// Calling this method on an unpinned array could result in memory corruption.</remarks>
|
||||||
|
/// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
|
||||||
|
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
|
||||||
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||||
|
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (<0 or >=Length).
|
||||||
|
/// </exception>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Memory<T> CreateFromPinnedArray<T>(T[]? array, int start, int length)
|
||||||
|
{
|
||||||
|
if (array == null)
|
||||||
|
{
|
||||||
|
if (start != 0 || length != 0)
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
if (!typeof(T).IsValueType && array.GetType() != typeof(T[]))
|
||||||
|
ThrowHelper.ThrowArrayTypeMismatchException();
|
||||||
|
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
|
||||||
|
ThrowHelper.ThrowArgumentOutOfRangeException();
|
||||||
|
|
||||||
|
// Before using _index, check if _index < 0, then 'and' it with RemoveFlagsBitMask
|
||||||
|
return new Memory<T>(/*(object)*/array, start | (1 << 31), length);
|
||||||
|
}
|
||||||
|
[DoesNotReturn]
|
||||||
|
private static void ThrowInvalidTypeWithPointersNotSupported(Type targetType)
|
||||||
|
=> throw new ArgumentException($"Cannot use type '{targetType}'.Only value types without pointers or references are supported.");
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// 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/Enumerables/ReadOnlySpanEnumerable%7BT%7D.cs
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see langword="ref"/> <see langword="struct"/> that enumerates the items in a given <see cref="ReadOnlySpan{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items to enumerate.</typeparam>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public ref struct ReadOnlySpanEnumerable<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The source <see cref="ReadOnlySpan{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ReadOnlySpan<T> _span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current index within <see cref="_span"/>.
|
||||||
|
/// </summary>
|
||||||
|
private int _index;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ReadOnlySpanEnumerable{T}"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> instance.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ReadOnlySpanEnumerable(ReadOnlySpan<T> span)
|
||||||
|
{
|
||||||
|
_span = span;
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the duck-typed <see cref="IEnumerable{T}.GetEnumerator"/> method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An <see cref="ReadOnlySpanEnumerable{T}"/> instance targeting the current <see cref="ReadOnlySpan{T}"/> value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly ReadOnlySpanEnumerable<T> GetEnumerator() => this;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the duck-typed <see cref="System.Collections.IEnumerator.MoveNext"/> method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><see langword="true"/> whether a new element is available, <see langword="false"/> otherwise</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext() => ++_index < _span.Length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the duck-typed <see cref="IEnumerator{T}.Current"/> property.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Item Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
// See comment in SpanEnumerable<T> about this
|
||||||
|
=> new(ref Unsafe.Add(ref _span.DangerousGetPinnableReference(), (nint)(uint)_index), _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An item from a source <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly ref struct Item
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The source <see cref="ReadOnlySpan{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ReadOnlySpan<T> _span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Item"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A reference to the target value.</param>
|
||||||
|
/// <param name="index">The index of the target value.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Item(ref T value, int index)
|
||||||
|
=> _span = MemoryMarshal.CreateReadOnlySpan(ref value, index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the reference to the current value.
|
||||||
|
/// </summary>
|
||||||
|
public ref readonly T Value
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => ref _span.DangerousGetPinnableReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current index.
|
||||||
|
/// </summary>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _span.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,574 @@
|
|||||||
|
// Based on
|
||||||
|
// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/ReadOnlySpanExtensions.cs
|
||||||
|
// with additional methods and support for more types
|
||||||
|
|
||||||
|
// 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 on https://github.com/CommunityToolkit/dotnet for more information.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
public static class ReadOnlySpanExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to an element at a specified index within a given <see cref="ReadOnlySpan{T}"/>, with no bounds checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
|
||||||
|
/// <param name="i">The index of the element to retrieve within <paramref name="span"/>.</param>
|
||||||
|
/// <returns>A reference to the element within <paramref name="span"/> at the index specified by <paramref name="i"/>.</returns>
|
||||||
|
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T DangerousGetReferenceAt<T>(this ReadOnlySpan<T> span, int i)
|
||||||
|
// Here we assume the input index will never be negative, so we do a (nint)(uint) cast
|
||||||
|
// to force the JIT to skip the sign extension when going from int to native int.
|
||||||
|
// On .NET Core 3.1, if we only use Unsafe.Add(ref r0, i), we get the following:
|
||||||
|
// =============================
|
||||||
|
// L0000: mov rax, [rcx]
|
||||||
|
// L0003: movsxd rdx, edx
|
||||||
|
// L0006: lea rax, [rax+rdx*4]
|
||||||
|
// L000a: ret
|
||||||
|
// =============================
|
||||||
|
// Note the movsxd (move with sign extension) to expand the index passed in edx to
|
||||||
|
// the whole rdx register. This is unnecessary and more expensive than just a mov,
|
||||||
|
// which when done to a large register size automatically zeroes the upper bits.
|
||||||
|
// With the (nint)(uint) cast, we get the following codegen instead:
|
||||||
|
// =============================
|
||||||
|
// L0000: mov rax, [rcx]
|
||||||
|
// L0003: mov edx, edx
|
||||||
|
// L0005: lea rax, [rax+rdx*4]
|
||||||
|
// L0009: ret
|
||||||
|
// =============================
|
||||||
|
// Here we can see how the index is extended to a native integer with just a mov,
|
||||||
|
// which effectively only zeroes the upper bits of the same register used as source.
|
||||||
|
// These three casts are a bit verbose, but they do the trick on both 32 bit and 64
|
||||||
|
// bit architectures, producing optimal code in both cases (they are either completely
|
||||||
|
// elided on 32 bit systems, or result in the correct register expansion when on 64 bit).
|
||||||
|
// We first do an unchecked conversion to uint (which is just a reinterpret-cast). We
|
||||||
|
// then cast to nint, so that we can obtain an IntPtr value without the range check (since
|
||||||
|
// uint could be out of range there if the original index was negative). The final result
|
||||||
|
// is a clean mov as shown above. This will eventually be natively supported by the JIT
|
||||||
|
// compiler (see https://github.com/dotnet/runtime/issues/38794), but doing this here
|
||||||
|
// still ensures the optimal codegen even on existing runtimes (eg. .NET Core 2.1 and 3.1).
|
||||||
|
=> ref Unsafe.Add(ref span.DangerousGetPinnableReference(), (nint)(uint)i);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to an element at a specified index within a given <see cref="ReadOnlySpan{T}"/>, with no bounds checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance.</param>
|
||||||
|
/// <param name="i">The index of the element to retrieve within <paramref name="span"/>.</param>
|
||||||
|
/// <returns>A reference to the element within <paramref name="span"/> at the index specified by <paramref name="i"/>.</returns>
|
||||||
|
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T DangerousGetReferenceAt<T>(this ReadOnlySpan<T> span, nint i)
|
||||||
|
=> ref Unsafe.Add(ref span.DangerousGetPinnableReference(), i);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T First<T>(this ReadOnlySpan<T> span)
|
||||||
|
=> span[0];
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T FirstOrDefault<T>(this ReadOnlySpan<T> span)
|
||||||
|
=> !span.IsEmpty ? span[0]
|
||||||
|
: default;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe TSource First<TSource>(this ReadOnlySpan<TSource> span, delegate*<TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThrowNotFoundException<TSource>();
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TSource First<TSource>(this ReadOnlySpan<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThrowNotFoundException<TSource>();
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
private static ref T ThrowNotFoundException<T>() => throw new InvalidOperationException();
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe TSource FirstOrDefault<TSource>(this ReadOnlySpan<TSource> span, delegate*<TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TSource FirstOrDefault<TSource>(this ReadOnlySpan<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Any<TSource>(this ReadOnlySpan<TSource> span)
|
||||||
|
=> !span.IsEmpty;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe bool Any<TSource>(this ReadOnlySpan<TSource> span, delegate*<TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 1))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 2))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Any<TSource>(this ReadOnlySpan<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 1))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 2))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of occurrences of a given value into a target <see cref="ReadOnlySpan{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance to read.</param>
|
||||||
|
/// <param name="value">The <typeparamref name="T"/> value to look for.</param>
|
||||||
|
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Count<T>(this ReadOnlySpan<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint result = 0;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
// Main loop with 4 unrolled iterations
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 1).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 2).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 3).Equals<T>(value).ToByte();
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the remaining values and count those that match
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals<T>(value).ToByte();
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this ReadOnlySpan<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 1).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 2).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 3).Equals<T>(value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this ReadOnlySpan<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return (int)offset;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 1).Equals<T>(value))
|
||||||
|
return (int)offset + 1;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 2).Equals<T>(value))
|
||||||
|
return (int)offset + 2;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 3).Equals<T>(value))
|
||||||
|
return (int)offset + 3;
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return (int)offset;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the items in the input <see cref="ReadOnlySpan{T}"/> instance, as pairs of reference/index values.
|
||||||
|
/// This extension should be used directly within a <see langword="foreach"/> loop:
|
||||||
|
/// <code>
|
||||||
|
/// ReadOnlySpan<int> numbers = new[] { 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
///
|
||||||
|
/// foreach (var item in numbers.Enumerate())
|
||||||
|
/// {
|
||||||
|
/// // Access the index and value of each item here...
|
||||||
|
/// int index = item.Index;
|
||||||
|
/// ref int value = ref item.Value;
|
||||||
|
/// }
|
||||||
|
/// </code>
|
||||||
|
/// The compiler will take care of properly setting up the <see langword="foreach"/> loop with the type returned from this method.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items to enumerate.</typeparam>
|
||||||
|
/// <param name="span">The source <see cref="ReadOnlySpan{T}"/> to enumerate.</param>
|
||||||
|
/// <returns>A wrapper type that will handle the reference/index enumeration for <paramref name="span"/>.</returns>
|
||||||
|
/// <remarks>The returned <see cref="ReadOnlySpanEnumerable{T}"/> value shouldn't be used directly: use this extension in a <see langword="foreach"/> loop.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ReadOnlySpanEnumerable<T> Enumerate<T>(this ReadOnlySpan<T> span) => new(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ReadOnlySpanReferenceExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of an element of a given <see cref="ReadOnlySpan{T}"/> from its reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/>.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> to calculate the index for.</param>
|
||||||
|
/// <param name="reference">The reference to the target item to get the index for.</param>
|
||||||
|
/// <returns>The index of <paramref name="reference"/> within <paramref name="span"/>, or <c>-1</c>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this ReadOnlySpan<T> span, ref T reference)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var byteOffset = Unsafe.ByteOffset(ref r0, ref reference);
|
||||||
|
|
||||||
|
var elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();
|
||||||
|
|
||||||
|
return (nuint)elementOffset >= (uint)span.Length ? -1
|
||||||
|
: (int)elementOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a reference points to an element within the <see cref="ReadOnlySpan{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/>.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> to locate the reference in.</param>
|
||||||
|
/// <param name="reference">The reference to the target item to locate.</param>
|
||||||
|
/// <returns>true if the reference points towards an element of <see cref="ReadOnlySpan{T}"/>; otherwise, false.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this ReadOnlySpan<T> span, ref T reference)
|
||||||
|
=> span.IndexOf(ref reference) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ReadOnlySpanStructExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of occurrences of a given value into a target <see cref="ReadOnlySpan{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="ReadOnlySpan{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> instance to read.</param>
|
||||||
|
/// <param name="value">The <typeparamref name="T"/> value to look for.</param>
|
||||||
|
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Count<T>(this ReadOnlySpan<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint result = 0;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
// Main loop with 4 unrolled iterations
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the remaining values and count those that match
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this ReadOnlySpan<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this ReadOnlySpan<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 1;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 2;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 3;
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using MonoMod.Utils;
|
||||||
|
using Verse;
|
||||||
|
using static Mono.Cecil.Mixin;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
public static class Reflection
|
||||||
|
{
|
||||||
|
public static CodeInstructions GetCodeInstructions(Delegate method)
|
||||||
|
=> PatchProcessor.GetCurrentInstructions(method.Method);
|
||||||
|
|
||||||
|
public static CodeInstructions GetCodeInstructions(Expression<Action> method)
|
||||||
|
=> PatchProcessor.GetCurrentInstructions(SymbolExtensions.GetMethodInfo(method));
|
||||||
|
|
||||||
|
public static CodeInstructions MakeReplacementCall(Delegate method)
|
||||||
|
=> MakeReplacementCall(method.Method);
|
||||||
|
|
||||||
|
public static CodeInstructions MakeReplacementCall(MethodInfo method)
|
||||||
|
{
|
||||||
|
if (!method.IsStatic)
|
||||||
|
yield return FishTranspiler.This;
|
||||||
|
|
||||||
|
foreach (var argument in method.GetParameters())
|
||||||
|
yield return FishTranspiler.Argument(argument);
|
||||||
|
|
||||||
|
yield return FishTranspiler.Call(method);
|
||||||
|
yield return FishTranspiler.Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type Type(string assembly, string type) => System.Type.GetType($"{type}, {assembly}");
|
||||||
|
|
||||||
|
public static MethodInfo MethodInfo<T>(T method) where T : Delegate => method.Method;
|
||||||
|
|
||||||
|
public static MethodInfo MethodInfo(string assembly, string type, string name, Type[]? parameters = null, Type[]? generics = null)
|
||||||
|
=> AccessTools.Method(Type(assembly, type), name, parameters, generics);
|
||||||
|
|
||||||
|
public static IEnumerable<MethodInfo> MethodsOfName(Type type, string name)
|
||||||
|
{
|
||||||
|
var methods = MethodsOfNameSilentFail(type, name).ToArray();
|
||||||
|
if (!methods.Any())
|
||||||
|
ThrowForMethodsOfName(type, name);
|
||||||
|
return methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ThrowForMethodsOfName(Type type, string name) => ThrowHelper.ThrowArgumentException($"No methods found for {type.FullDescription()}:{name}");
|
||||||
|
|
||||||
|
public static IEnumerable<MethodInfo> MethodsOfNameSilentFail(Type type, string name)
|
||||||
|
=> type?.GetMethods(AccessTools.allDeclared)
|
||||||
|
.Where(m => m.Name == name)
|
||||||
|
?? Enumerable.Empty<MethodInfo>();
|
||||||
|
|
||||||
|
public static FieldInfo FieldInfo(string assembly, string type, string name) => AccessTools.Field(Type(assembly, type), name);
|
||||||
|
|
||||||
|
public static bool IsAssignableTo(this Type type, [NotNullWhen(true)] Type? targetType, params Type[] generics)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(type);
|
||||||
|
|
||||||
|
return targetType != null
|
||||||
|
&& (generics is { Length: >= 1 }
|
||||||
|
? targetType.MakeGenericType(generics)
|
||||||
|
: targetType)
|
||||||
|
.IsAssignableFrom(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AreAssignableFrom(this IEnumerable<Type> types, IEnumerable<Type> targetTypes)
|
||||||
|
=> targetTypes.AreAssignableTo(types);
|
||||||
|
|
||||||
|
public static bool AreAssignableTo(this IEnumerable<Type> types, IEnumerable<Type> targetTypes)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(types);
|
||||||
|
Guard.IsNotNull(targetTypes);
|
||||||
|
|
||||||
|
using var typesEnumerator = types.GetEnumerator();
|
||||||
|
using var targetTypesEnumerator = targetTypes.GetEnumerator();
|
||||||
|
|
||||||
|
while (typesEnumerator.MoveNext())
|
||||||
|
{
|
||||||
|
if (!targetTypesEnumerator.MoveNext()
|
||||||
|
|| !targetTypesEnumerator.Current.IsAssignableFrom(typesEnumerator.Current))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !targetTypesEnumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsNullable(this Type type)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(type);
|
||||||
|
|
||||||
|
return type.IsGenericType
|
||||||
|
&& type.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsNullable(this Type nullableType, [NotNullWhen(true)] out Type? valueType)
|
||||||
|
{
|
||||||
|
if (nullableType.IsNullable())
|
||||||
|
{
|
||||||
|
valueType = nullableType.GetGenericArguments()[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueType = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasGenericInterfaceDefinition(this Type type, Type interfaceType)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(type);
|
||||||
|
|
||||||
|
return Array.Exists(type.GetInterfaces(), @interface
|
||||||
|
=> @interface.IsGenericType
|
||||||
|
&& @interface.GetGenericTypeDefinition() == interfaceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe IntPtr GetFunctionPointer(this MethodBase method) => method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T> GetFunctionPointer<T>(this MethodBase method) => (delegate*<T>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T_in, T_out> GetFunctionPointer<T_in, T_out>(this MethodBase method) => (delegate*<T_in, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T_out> GetFunctionPointer<T1, T2, T_out>(this MethodBase method) => (delegate*<T1, T2, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T3, T_out> GetFunctionPointer<T1, T2, T3, T_out>(this MethodBase method) => (delegate*<T1, T2, T3, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T3, T4, T_out> GetFunctionPointer<T1, T2, T3, T4, T_out>(this MethodBase method) => (delegate*<T1, T2, T3, T4, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T3, T4, T5, T_out> GetFunctionPointer<T1, T2, T3, T4, T5, T_out>(this MethodBase method) => (delegate*<T1, T2, T3, T4, T5, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T3, T4, T5, T6, T_out> GetFunctionPointer<T1, T2, T3, T4, T5, T6, T_out>(this MethodBase method) => (delegate*<T1, T2, T3, T4, T5, T6, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
public static unsafe delegate*<T1, T2, T3, T4, T5, T6, T7, T_out> GetFunctionPointer<T1, T2, T3, T4, T5, T6, T7, T_out>(this MethodBase method) => (delegate*<T1, T2, T3, T4, T5, T6, T7, T_out>)method.MethodHandle.GetFunctionPointer();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a constructor with parameters that are either assignable to or assignable from the types in the provided parameters array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the object to construct</param>
|
||||||
|
/// <param name="parameters">An array of parameter types that are either assignable to or from the parameters of a constructor for the target type</param>
|
||||||
|
/// <param name="searchForStatic">Search for static constructors instead of instance constructors</param>
|
||||||
|
/// <param name="throwOnFailure">Throw an exception on failure to find a matching constructor</param>
|
||||||
|
/// <returns>A ConstructorInfo that best matches the provided arguments. Null on failure if throwOnFailure is set to false</returns>
|
||||||
|
public static ConstructorInfo? MatchingConstructor(Type type, Type[]? parameters = null, bool searchForStatic = false, bool throwOnFailure = true)
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(type);
|
||||||
|
|
||||||
|
parameters ??= Array.Empty<Type>();
|
||||||
|
var flags = searchForStatic ? (AccessTools.all & ~BindingFlags.Instance) : (AccessTools.all & ~BindingFlags.Static);
|
||||||
|
|
||||||
|
return TryGetConstructor(type, flags, paramTypes => paramTypes.AreAssignableFrom(parameters))
|
||||||
|
?? TryGetConstructor(type, flags, paramTypes => paramTypes.AreAssignableTo(parameters))
|
||||||
|
?? (throwOnFailure ? ThrowHelper.ThrowInvalidOperationException<ConstructorInfo>(
|
||||||
|
$"No constructor found for type: {type}, parameters: {parameters.ToStringSafeEnumerable()}, static: {searchForStatic}, found constructors: {type.GetConstructors(flags).ToStringSafeEnumerable()}")
|
||||||
|
: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConstructorInfo TryGetConstructor(Type type, BindingFlags flags, Predicate<IEnumerable<Type>> predicate)
|
||||||
|
=> type.GetConstructors(flags).FirstOrDefault(c
|
||||||
|
=> predicate(c.GetParameters().Select(p => p.ParameterType)));
|
||||||
|
|
||||||
|
private static Delegate MakeStructDefaultConstructor(Type type)
|
||||||
|
{
|
||||||
|
var dm = new DynamicMethod("StructDefaultConstructor", type, Array.Empty<Type>(), type, true);
|
||||||
|
var il = dm.GetILGenerator();
|
||||||
|
|
||||||
|
var variable = il.DeclareLocal(type);
|
||||||
|
|
||||||
|
il.Emit(FishTranspiler.LocalVariable(variable).Address());
|
||||||
|
il.Emit(FishTranspiler.New(type));
|
||||||
|
il.Emit(FishTranspiler.LocalVariable(variable));
|
||||||
|
il.Emit(FishTranspiler.Return);
|
||||||
|
|
||||||
|
return dm.CreateDelegate(typeof(Func<>).MakeGenericType(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T New<T>()
|
||||||
|
=> Create<T>.@new();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T_result New<T_result, T_argument>(T_argument argument)
|
||||||
|
=> Create<T_result, T_argument>.@new(argument);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T_result New<T_result, T1, T2>(T1 arg1, T2 arg2)
|
||||||
|
=> Create<T_result, T1, T2>.@new(arg1, arg2);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T_result New<T_result, T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3)
|
||||||
|
=> Create<T_result, T1, T2, T3>.@new(arg1, arg2, arg3);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T_result New<T_result, T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
|
||||||
|
=> Create<T_result, T1, T2, T3, T4>.@new(arg1, arg2, arg3, arg4);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T_result New<T_result, T1, T2, T3, T4, T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
|
||||||
|
=> Create<T_result, T1, T2, T3, T4, T5>.@new(arg1, arg2, arg3, arg4, arg5);
|
||||||
|
|
||||||
|
private static class Create<T>
|
||||||
|
{
|
||||||
|
internal static Func<T> @new
|
||||||
|
= typeof(T).IsValueType ? (Func<T>)MakeStructDefaultConstructor(typeof(T))
|
||||||
|
: MatchingConstructor(typeof(T), Array.Empty<Type>())!.CreateDelegate<Func<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T_result, T_argument>
|
||||||
|
{
|
||||||
|
internal static Func<T_argument, T_result> @new
|
||||||
|
= MatchingConstructor(typeof(T_result), new[] { typeof(T_argument) })!.CreateDelegate<Func<T_argument, T_result>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T_result, T1, T2>
|
||||||
|
{
|
||||||
|
internal static Func<T1, T2, T_result> @new
|
||||||
|
= MatchingConstructor(typeof(T_result), new[] { typeof(T1), typeof(T2) })!.CreateDelegate<Func<T1, T2, T_result>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T_result, T1, T2, T3>
|
||||||
|
{
|
||||||
|
internal static Func<T1, T2, T3, T_result> @new
|
||||||
|
= MatchingConstructor(typeof(T_result), new[] { typeof(T1), typeof(T2), typeof(T3) })!.CreateDelegate<Func<T1, T2, T3, T_result>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T_result, T1, T2, T3, T4>
|
||||||
|
{
|
||||||
|
internal static Func<T1, T2, T3, T4, T_result> @new
|
||||||
|
= MatchingConstructor(typeof(T_result), new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) })!.CreateDelegate<Func<T1, T2, T3, T4, T_result>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T_result, T1, T2, T3, T4, T5>
|
||||||
|
{
|
||||||
|
internal static Func<T1, T2, T3, T4, T5, T_result> @new
|
||||||
|
= MatchingConstructor(typeof(T_result), new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) })!.CreateDelegate<Func<T1, T2, T3, T4, T5, T_result>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// 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.Concurrent;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
public abstract class SingletonFactory<T_base> where T_base : notnull
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Singleton instance of a type derived from T_base
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the instance</typeparam>
|
||||||
|
/// <returns>The Singleton instance</returns>
|
||||||
|
public static T Get<T>() where T : T_base
|
||||||
|
=> (T)GetInternal(typeof(T));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Singleton instance of a type derived from T_base
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type of the instance</param>
|
||||||
|
/// <returns>The Singleton instance</returns>
|
||||||
|
public static T_base Get(Type type)
|
||||||
|
{
|
||||||
|
if (!typeof(T_base).IsAssignableFrom(type))
|
||||||
|
ThrowHelper.ThrowArgumentException($"Parameters for {typeof(T_base).Name}.Get must be assignable from Type {typeof(T_base).Name}. Got {type.FullDescription()} instead.");
|
||||||
|
|
||||||
|
return GetInternal(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// protected to allow declaring of default values on derived types. Do not directly invoke this constructor or expose it as public.
|
||||||
|
/// </summary>
|
||||||
|
protected SingletonFactory()
|
||||||
|
{
|
||||||
|
if (_instances.ContainsKey(GetType()))
|
||||||
|
ThrowHelper.ThrowInvalidOperationException($"Tried creating a second instance of {GetType().Name}. Only the {typeof(T_base).Name}.Get method should be used for instantiation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T_base GetInternal(Type type) => _instances.GetOrAdd(type, type => (T_base)Activator.CreateInstance(type, true));
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<Type, T_base> _instances = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// 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/Enumerables/SpanEnumerable%7BT%7D.cs
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <see langword="ref"/> <see langword="struct"/> that enumerates the items in a given <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items to enumerate.</typeparam>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public ref struct SpanEnumerable<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The source <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Span<T> _span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current index within <see cref="_span"/>.
|
||||||
|
/// </summary>
|
||||||
|
private int _index;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SpanEnumerable{T}"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="span">The source <see cref="Span{T}"/> instance.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public SpanEnumerable(Span<T> span)
|
||||||
|
{
|
||||||
|
_span = span;
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the duck-typed <see cref="IEnumerable{T}.GetEnumerator"/> method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An <see cref="SpanEnumerable{T}"/> instance targeting the current <see cref="Span{T}"/> value.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly SpanEnumerable<T> GetEnumerator() => this;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implements the duck-typed <see cref="System.Collections.IEnumerator.MoveNext"/> method.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><see langword="true"/> whether a new element is available, <see langword="false"/> otherwise</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext() => ++_index < _span.Length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the duck-typed <see cref="IEnumerator{T}.Current"/> property.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Item Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get
|
||||||
|
// On .NET Standard 2.1 and .NET Core (or on any target that offers runtime
|
||||||
|
// support for the Span<T> types), we can save 4 bytes by piggybacking the
|
||||||
|
// current index in the length of the wrapped span. We're going to use the
|
||||||
|
// first item as the target reference, and the length as a host for the
|
||||||
|
// current original offset. This is not possible on eg. .NET Standard 2.0,
|
||||||
|
// as we lack the API to create Span<T>-s from arbitrary references.
|
||||||
|
=> new(ref Unsafe.Add(ref _span.DangerousGetPinnableReference(), (nint)(uint)_index), _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An item from a source <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly ref struct Item
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The source <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Span<T> _span;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Item"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">A reference to the target value.</param>
|
||||||
|
/// <param name="index">The index of the target value.</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Item(ref T value, int index) => _span = MemoryMarshal.CreateSpan(ref value, index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the reference to the current value.
|
||||||
|
/// </summary>
|
||||||
|
public ref T Value
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => ref MemoryMarshal.GetReference(_span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current index.
|
||||||
|
/// </summary>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _span.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,552 @@
|
|||||||
|
// Based on
|
||||||
|
// https://github.com/CommunityToolkit/dotnet/blob/main/CommunityToolkit.HighPerformance/Extensions/SpanExtensions.cs
|
||||||
|
// with additional methods and support for more types
|
||||||
|
|
||||||
|
// 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 on https://github.com/CommunityToolkit/dotnet for more information.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
public static class SpanExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to an element at a specified index within a given <see cref="Span{T}"/>, with no bounds checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the input <see cref="Span{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <param name="i">The index of the element to retrieve within <paramref name="span"/>.</param>
|
||||||
|
/// <returns>A reference to the element within <paramref name="span"/> at the index specified by <paramref name="i"/>.</returns>
|
||||||
|
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T DangerousGetReferenceAt<T>(this Span<T> span, int i)
|
||||||
|
=> ref Unsafe.Add(ref span.DangerousGetPinnableReference(), (nint)(uint)i);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to an element at a specified index within a given <see cref="Span{T}"/>, with no bounds checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the input <see cref="Span{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <param name="i">The index of the element to retrieve within <paramref name="span"/>.</param>
|
||||||
|
/// <returns>A reference to the element within <paramref name="span"/> at the index specified by <paramref name="i"/>.</returns>
|
||||||
|
/// <remarks>This method doesn't do any bounds checks, therefore it is responsibility of the caller to ensure the <paramref name="i"/> parameter is valid.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T DangerousGetReferenceAt<T>(this Span<T> span, nint i)
|
||||||
|
=> ref Unsafe.Add(ref span.DangerousGetPinnableReference(), i);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Sort<T>(this Span<T> span, IComparer<T>? comparer)
|
||||||
|
=> ArraySortHelper<T>.Default.Sort(span, comparer);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Sort<TKey, TValue>(this Span<TValue> values, Span<TKey> keys, IComparer<TKey>? comparer)
|
||||||
|
=> ArraySortHelper<TKey, TValue>.Default.Sort(keys, values, comparer);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T First<T>(this Span<T> span)
|
||||||
|
=> ref span[0];
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T FirstOrDefault<T>(this Span<T> span)
|
||||||
|
=> !span.IsEmpty ? span[0]
|
||||||
|
: default;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe ref TSource First<TSource>(this Span<TSource> span, delegate*<ref TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref ThrowNotFoundException<TSource>();
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return ref Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref TSource First<TSource>(this Span<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return ref Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref ThrowNotFoundException<TSource>();
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return ref Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
private static ref T ThrowNotFoundException<T>() => throw new InvalidOperationException();
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe TSource FirstOrDefault<TSource>(this Span<TSource> span, delegate*<ref TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[return: MaybeNull]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TSource FirstOrDefault<TSource>(this Span<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 1)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 1);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 2)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 2);
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
return Unsafe.Add(ref r0, offset + 3);
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
goto returnForOffset0;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
|
||||||
|
returnForOffset0:
|
||||||
|
return Unsafe.Add(ref r0, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Any<TSource>(this Span<TSource> span)
|
||||||
|
=> !span.IsEmpty;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static unsafe bool Any<TSource>(this Span<TSource> span, delegate*<ref TSource, bool> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset))
|
||||||
|
|| predicate(ref Unsafe.Add(ref r0, offset + 1))
|
||||||
|
|| predicate(ref Unsafe.Add(ref r0, offset + 2))
|
||||||
|
|| predicate(ref Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(ref Unsafe.Add(ref r0, offset)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Any<TSource>(this Span<TSource> span, Predicate<TSource> predicate)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 1))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 2))
|
||||||
|
|| predicate(Unsafe.Add(ref r0, offset + 3)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (predicate(Unsafe.Add(ref r0, offset)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of occurrences of a given value into a target <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> instance to read.</param>
|
||||||
|
/// <param name="value">The <typeparamref name="T"/> value to look for.</param>
|
||||||
|
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Count<T>(this Span<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint result = 0;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
// Main loop with 4 unrolled iterations
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 1).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 2).Equals<T>(value).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 3).Equals<T>(value).ToByte();
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the remaining values and count those that match
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals<T>(value).ToByte();
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this Span<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 1).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 2).Equals<T>(value)
|
||||||
|
|| Unsafe.Add(ref r0, offset + 3).Equals<T>(value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this Span<T> span, T value)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return (int)offset;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 1).Equals<T>(value))
|
||||||
|
return (int)offset + 1;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 2).Equals<T>(value))
|
||||||
|
return (int)offset + 2;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 3).Equals<T>(value))
|
||||||
|
return (int)offset + 3;
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals<T>(value))
|
||||||
|
return (int)offset;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the items in the input <see cref="Span{T}"/> instance, as pairs of reference/index values.
|
||||||
|
/// This extension should be used directly within a <see langword="foreach"/> loop:
|
||||||
|
/// <code>
|
||||||
|
/// Span<int> numbers = new[] { 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
///
|
||||||
|
/// foreach (var item in numbers.Enumerate())
|
||||||
|
/// {
|
||||||
|
/// // Access the index and value of each item here...
|
||||||
|
/// int index = item.Index;
|
||||||
|
/// ref int value = ref item.Value;
|
||||||
|
/// }
|
||||||
|
/// </code>
|
||||||
|
/// The compiler will take care of properly setting up the <see langword="foreach"/> loop with the type returned from this method.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items to enumerate.</typeparam>
|
||||||
|
/// <param name="span">The source <see cref="Span{T}"/> to enumerate.</param>
|
||||||
|
/// <returns>A wrapper type that will handle the reference/index enumeration for <paramref name="span"/>.</returns>
|
||||||
|
/// <remarks>The returned <see cref="SpanEnumerable{T}"/> value shouldn't be used directly: use this extension in a <see langword="foreach"/> loop.</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static SpanEnumerable<T> Enumerate<T>(this Span<T> span) => new(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SpanReferenceExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index of an element of a given <see cref="Span{T}"/> from its reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/>.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> to calculate the index for.</param>
|
||||||
|
/// <param name="reference">The reference to the target item to get the index for.</param>
|
||||||
|
/// <returns>The index of <paramref name="reference"/> within <paramref name="span"/>, or <c>-1</c>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this Span<T> span, ref T reference)
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var byteOffset = Unsafe.ByteOffset(ref r0, ref reference);
|
||||||
|
|
||||||
|
var elementOffset = byteOffset / (nint)(uint)Unsafe.SizeOf<T>();
|
||||||
|
|
||||||
|
return (nuint)elementOffset >= (uint)span.Length ? -1
|
||||||
|
: (int)elementOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a reference points to an element within the <see cref="Span{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/>.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> to locate the reference in.</param>
|
||||||
|
/// <param name="reference">The reference to the target item to locate.</param>
|
||||||
|
/// <returns>true if the reference points towards an element of <see cref="Span{T}"/>; otherwise, false.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this Span<T> span, ref T reference)
|
||||||
|
=> span.IndexOf(ref reference) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SpanStructExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of occurrences of a given value into a target <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of items in the input <see cref="Span{T}"/> instance.</typeparam>
|
||||||
|
/// <param name="span">The input <see cref="Span{T}"/> instance to read.</param>
|
||||||
|
/// <param name="value">The <typeparamref name="T"/> value to look for.</param>
|
||||||
|
/// <returns>The number of occurrences of <paramref name="value"/> in <paramref name="span"/>.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int Count<T>(this Span<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint result = 0;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
// Main loop with 4 unrolled iterations
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
result += Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the remaining values and count those that match
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
result += Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)).ToByte();
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains<T>(this Span<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value))
|
||||||
|
|| Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static int IndexOf<T>(this Span<T> span, in T value)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
ref var r0 = ref span.DangerousGetPinnableReference();
|
||||||
|
var length = (nint)(uint)span.Length;
|
||||||
|
nint offset = 0;
|
||||||
|
|
||||||
|
while (length >= 4)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 1).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 1;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 2).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 2;
|
||||||
|
if (Unsafe.Add(ref r0, offset + 3).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset + 3;
|
||||||
|
|
||||||
|
length -= 4;
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (length > 0)
|
||||||
|
{
|
||||||
|
if (Unsafe.Add(ref r0, offset).Equals(ref Unsafe.AsRef(in value)))
|
||||||
|
return (int)offset;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// 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;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FisheryLib;
|
||||||
|
|
||||||
|
internal static class UtilityF
|
||||||
|
{
|
||||||
|
internal static void ThrowIfNullOrEmpty<T>(IEnumerable<T> sequence, [CallerArgumentExpression(nameof(sequence))] string argumentName = "")
|
||||||
|
{
|
||||||
|
Guard.IsNotNull(sequence, argumentName);
|
||||||
|
|
||||||
|
if (!sequence.Any())
|
||||||
|
ThrowHelper.ThrowArgumentException("Sequence contains no elements", argumentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
internal static void Throw(string message) => throw new(message);
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
internal static void Throw<T>(string message) where T : Exception => throw (T)Activator.CreateInstance(typeof(T), message);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
internal static Assembly GetCallingAssembly()
|
||||||
|
{
|
||||||
|
Assembly? fishAssembly = null;
|
||||||
|
var stacktrace = new StackTrace();
|
||||||
|
|
||||||
|
for (var i = 0; i < stacktrace.FrameCount; i++)
|
||||||
|
{
|
||||||
|
var assembly = stacktrace.GetFrame(i).GetMethod().ReflectedType.Assembly;
|
||||||
|
fishAssembly ??= assembly;
|
||||||
|
|
||||||
|
if (assembly != fishAssembly)
|
||||||
|
return assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Assembly.GetCallingAssembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*internal static T New<T>() => Create<T>.@new();
|
||||||
|
|
||||||
|
internal static T New<T, V>(V argument) => Create<T, V>.@new(argument);
|
||||||
|
|
||||||
|
internal static T New<T, V, W>(V firstArgument, W secondArgument) => Create<T, V, W>.@new(firstArgument, secondArgument);
|
||||||
|
|
||||||
|
private static class Create<T>
|
||||||
|
{
|
||||||
|
internal static Func<T> @new = AccessTools.Constructor(typeof(T)).CreateDelegate<Func<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T, V>
|
||||||
|
{
|
||||||
|
internal static Func<V, T> @new = AccessTools.Constructor(typeof(T), new[] { typeof(V) }).CreateDelegate<Func<V, T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Create<T, V, W>
|
||||||
|
{
|
||||||
|
internal static Func<V, W, T> @new = AccessTools.Constructor(typeof(T), new[] { typeof(V), typeof(W) }).CreateDelegate<Func<V, W, T>>();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user