├── .editorconfig
├── .gitignore
├── .paket
└── Paket.Restore.targets
├── CSharpx.sln
├── Directory.Build.props
├── LICENSE
├── README.md
├── assets
└── icon.png
├── paket-files
├── .gitignore
└── paket.restore.cached
├── paket.dependencies
├── paket.lock
├── src
├── .editorconfig
└── CSharpx
│ ├── CSharpx.csproj
│ ├── CryptoRandom.cs
│ ├── Either.cs
│ ├── EnumerableExtensions.cs
│ ├── ExceptionExtensions.cs
│ ├── FSharpResultExtensions.cs
│ ├── Maybe.cs
│ ├── Result.cs
│ ├── Strings.cs
│ ├── Unit.cs
│ └── paket.references
└── tests
└── CSharpx.Specs
├── CSharpx.Specs.csproj
├── Fakes
└── Arbitrary.cs
├── Outcomes
├── CharExtensionsSpecs..cs
├── EitherSpecs.cs
├── EnumerableExtensionsSpecs.cs
├── FSharpResultExtensionsSpecs.cs
├── MaybeSpecs.cs
├── ResultSpecs.cs
├── StringExtensionsSpecs.cs
├── StringUtilSpecs.cs
└── UnitSpecs.cs
└── paket.references
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | []
4 | end_of_line = crlf
5 | insert_final_newline = false
6 |
7 | [*.xml]
8 | indent_style = space
9 | indent_size = 4
10 |
11 | [*.{json,yml}]
12 | indent_style = space
13 | indent_size = 2
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | .DS_Store
3 | .vscode/
4 | .vs
5 | tools/
6 | [Oo]bj/
7 | [Bb]in/
8 | .nuget/
9 | _ReSharper.*
10 | packages/
11 | artifacts/
12 | *.user
13 | *.suo
14 | *.userprefs
15 | *DS_Store
16 | *.sln.ide
--------------------------------------------------------------------------------
/.paket/Paket.Restore.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
8 |
9 | $(MSBuildVersion)
10 | 15.0.0
11 | false
12 | true
13 |
14 | true
15 | $(MSBuildThisFileDirectory)
16 | $(MSBuildThisFileDirectory)..\
17 | $(PaketRootPath)paket-files\paket.restore.cached
18 | $(PaketRootPath)paket.lock
19 | classic
20 | proj
21 | assembly
22 | native
23 | /Library/Frameworks/Mono.framework/Commands/mono
24 | mono
25 |
26 |
27 | $(PaketRootPath)paket.bootstrapper.exe
28 | $(PaketToolsPath)paket.bootstrapper.exe
29 | $([System.IO.Path]::GetDirectoryName("$(PaketBootStrapperExePath)"))\
30 |
31 | "$(PaketBootStrapperExePath)"
32 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"
33 |
34 |
35 |
36 |
37 | true
38 | true
39 |
40 |
41 | True
42 |
43 |
44 | False
45 |
46 | $(BaseIntermediateOutputPath.TrimEnd('\').TrimEnd('\/'))
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | $(PaketRootPath)paket
56 | $(PaketToolsPath)paket
57 |
58 |
59 |
60 |
61 |
62 | $(PaketRootPath)paket.exe
63 | $(PaketToolsPath)paket.exe
64 |
65 |
66 |
67 |
68 |
69 | <_DotnetToolsJson Condition="Exists('$(PaketRootPath)/.config/dotnet-tools.json')">$([System.IO.File]::ReadAllText("$(PaketRootPath)/.config/dotnet-tools.json"))
70 | <_ConfigContainsPaket Condition=" '$(_DotnetToolsJson)' != ''">$(_DotnetToolsJson.Contains('"paket"'))
71 | <_ConfigContainsPaket Condition=" '$(_ConfigContainsPaket)' == ''">false
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | <_PaketCommand>dotnet paket
83 |
84 |
85 |
86 |
87 |
88 | $(PaketToolsPath)paket
89 | $(PaketBootStrapperExeDir)paket
90 |
91 |
92 | paket
93 |
94 |
95 |
96 |
97 | <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))
98 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(_PaketExeExtension)' == '.dll' ">dotnet "$(PaketExePath)"
99 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' AND '$(OS)' != 'Windows_NT' AND '$(_PaketExeExtension)' == '.exe' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
100 | <_PaketCommand Condition=" '$(_PaketCommand)' == '' ">"$(PaketExePath)"
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | true
122 | $(NoWarn);NU1603;NU1604;NU1605;NU1608
123 | false
124 | true
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))
134 |
135 |
136 |
137 |
138 |
139 |
141 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))
142 | $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))
143 |
144 |
145 |
146 |
147 | %(PaketRestoreCachedKeyValue.Value)
148 | %(PaketRestoreCachedKeyValue.Value)
149 |
150 |
151 |
152 |
153 | true
154 | false
155 | true
156 |
157 |
158 |
162 |
163 | true
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | $(PaketIntermediateOutputPath)\$(MSBuildProjectFile).paket.references.cached
183 |
184 | $(MSBuildProjectFullPath).paket.references
185 |
186 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references
187 |
188 | $(MSBuildProjectDirectory)\paket.references
189 |
190 | false
191 | true
192 | true
193 | references-file-or-cache-not-found
194 |
195 |
196 |
197 |
198 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))
199 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))
200 | references-file
201 | false
202 |
203 |
204 |
205 |
206 | false
207 |
208 |
209 |
210 |
211 | true
212 | target-framework '$(TargetFramework)' or '$(TargetFrameworks)' files @(PaketResolvedFilePaths)
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 | false
224 | true
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',').Length)
236 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])
237 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])
238 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])
239 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[5])
240 |
241 |
242 | %(PaketReferencesFileLinesInfo.PackageVersion)
243 | All
244 | runtime
245 | runtime
246 | true
247 | true
248 |
249 |
250 |
251 |
252 | $(PaketIntermediateOutputPath)/$(MSBuildProjectFile).paket.clitools
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])
262 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])
263 |
264 |
265 | %(PaketCliToolFileLinesInfo.PackageVersion)
266 |
267 |
268 |
269 |
273 |
274 |
275 |
276 |
277 |
278 | false
279 |
280 |
281 |
282 |
283 |
284 | <_NuspecFilesNewLocation Include="$(PaketIntermediateOutputPath)\$(Configuration)\*.nuspec"/>
285 |
286 |
287 |
288 |
289 |
290 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile)
291 | true
292 | false
293 | true
294 | false
295 | true
296 | false
297 | true
298 | false
299 | true
300 | $(PaketIntermediateOutputPath)\$(Configuration)
301 | $(PaketIntermediateOutputPath)
302 |
303 |
304 |
305 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.$(PackageVersion.Split(`+`)[0]).nuspec"/>
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
363 |
364 |
407 |
408 |
450 |
451 |
492 |
493 |
494 |
495 |
--------------------------------------------------------------------------------
/CSharpx.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpx", "src/CSharpx/CSharpx.csproj", "{2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpx.Specs", "tests/CSharpx.Specs/CSharpx.Specs.csproj", "{BBDB5904-5A75-49E7-A57E-EB92E32A7527}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|x64.ActiveCfg = Debug|Any CPU
26 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|x64.Build.0 = Debug|Any CPU
27 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|x86.ActiveCfg = Debug|Any CPU
28 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Debug|x86.Build.0 = Debug|Any CPU
29 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|x64.ActiveCfg = Release|Any CPU
32 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|x64.Build.0 = Release|Any CPU
33 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|x86.ActiveCfg = Release|Any CPU
34 | {2F3B15E9-0A38-4B2C-8304-78566D1BC3ED}.Release|x86.Build.0 = Release|Any CPU
35 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|x64.ActiveCfg = Debug|Any CPU
38 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|x64.Build.0 = Debug|Any CPU
39 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|x86.ActiveCfg = Debug|Any CPU
40 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Debug|x86.Build.0 = Debug|Any CPU
41 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|x64.ActiveCfg = Release|Any CPU
44 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|x64.Build.0 = Release|Any CPU
45 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|x86.ActiveCfg = Release|Any CPU
46 | {BBDB5904-5A75-49E7-A57E-EB92E32A7527}.Release|x86.Build.0 = Release|Any CPU
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(MSBuildThisFileDirectory)
4 | false
5 |
6 |
7 | $(DefineConstants);NETFRAMEWORK
8 |
9 |
10 |
11 |
12 | runtime; build; native; contentfiles; analyzers
13 | all
14 |
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2015 - 2021 Giacomo Stelluti Scala
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This repository is no longer maintained
2 |
3 | Issue reports and pull requests will not be attended.
4 |
5 | Development has been moved to **SharpX** project.
6 |
7 | * SharpX: [View on GitHub](https://github.com/gsscoder/sharpx).
8 |
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gsscoder/CSharpx/280d8f9aa741721129942af6ae8f5fc0ea689fb3/assets/icon.png
--------------------------------------------------------------------------------
/paket-files/.gitignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | paket.restore.cached
--------------------------------------------------------------------------------
/paket-files/paket.restore.cached:
--------------------------------------------------------------------------------
1 | {
2 | "packagesDownloadedHash": "6B2E26D9EDA25D28CDD720E738C17FB4ED33446ADA4FA14898AAE2636705EDC2",
3 | "projectsRestoredHash": "6B2E26D9EDA25D28CDD720E738C17FB4ED33446ADA4FA14898AAE2636705EDC2"
4 | }
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://www.nuget.org/api/v2
2 |
3 | nuget coverlet.collector 1.0.1
4 | nuget FluentAssertions 5.10.3
5 | nuget FsCheck 3.0.0-alpha4 prerelease
6 | nuget FsCheck.Xunit 3.0.0-alpha4 prerelease
7 | nuget Microsoft.NET.Test.Sdk 16.2.0
8 | nuget xunit 2.4.0
9 | nuget xunit.runner.visualstudio 2.4.0
10 | nuget FSharp.Core 4.7.0
--------------------------------------------------------------------------------
/src/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{csproj,config}]
2 | indent_style = space
3 | indent_size = 2
4 |
5 | # C# files
6 | [*.cs]
7 |
8 | #### Core EditorConfig Options ####
9 |
10 | # Indentation and spacing
11 | indent_size = 4
12 | indent_style = space
13 | tab_width = 4
14 |
15 | # New line preferences
16 | end_of_line = crlf
17 | insert_final_newline = false
18 |
19 | #### .NET Coding Conventions ####
20 |
21 | # Organize usings
22 | dotnet_separate_import_directive_groups = false
23 | dotnet_sort_system_directives_first = true
24 | file_header_template = unset
25 |
26 | # this. and Me. preferences
27 | dotnet_style_qualification_for_event = false
28 | dotnet_style_qualification_for_field = false
29 | dotnet_style_qualification_for_method = false
30 | dotnet_style_qualification_for_property = false
31 |
32 | # Language keywords vs BCL types preferences
33 | dotnet_style_predefined_type_for_locals_parameters_members = true
34 | dotnet_style_predefined_type_for_member_access = true
35 |
36 | # Parentheses preferences
37 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
38 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
39 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary
40 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
41 |
42 | # Modifier preferences
43 | dotnet_style_require_accessibility_modifiers = for_non_interface_members
44 |
45 | # Expression-level preferences
46 | dotnet_style_coalesce_expression = true
47 | dotnet_style_collection_initializer = true
48 | dotnet_style_explicit_tuple_names = true
49 | dotnet_style_null_propagation = true
50 | dotnet_style_object_initializer = true
51 | dotnet_style_operator_placement_when_wrapping = beginning_of_line
52 | dotnet_style_prefer_auto_properties = true
53 | dotnet_style_prefer_compound_assignment = true
54 | dotnet_style_prefer_conditional_expression_over_assignment = true
55 | dotnet_style_prefer_conditional_expression_over_return = true
56 | dotnet_style_prefer_inferred_anonymous_type_member_names = true
57 | dotnet_style_prefer_inferred_tuple_names = true
58 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true
59 | dotnet_style_prefer_simplified_boolean_expressions = true
60 | dotnet_style_prefer_simplified_interpolation = true
61 |
62 | # Field preferences
63 | dotnet_style_readonly_field = true
64 |
65 | # Parameter preferences
66 | dotnet_code_quality_unused_parameters = all
67 |
68 | # Suppression preferences
69 | dotnet_remove_unnecessary_suppression_exclusions = none
70 |
71 | #### C# Coding Conventions ####
72 |
73 | # var preferences
74 | csharp_style_var_elsewhere = false
75 | csharp_style_var_for_built_in_types = false
76 | csharp_style_var_when_type_is_apparent = false
77 |
78 | # Expression-bodied members
79 | csharp_style_expression_bodied_accessors = true
80 | csharp_style_expression_bodied_constructors = false
81 | csharp_style_expression_bodied_indexers = true
82 | csharp_style_expression_bodied_lambdas = true
83 | csharp_style_expression_bodied_local_functions = false
84 | csharp_style_expression_bodied_methods = false
85 | csharp_style_expression_bodied_operators = false
86 | csharp_style_expression_bodied_properties = true
87 |
88 | # Pattern matching preferences
89 | csharp_style_pattern_matching_over_as_with_null_check = true
90 | csharp_style_pattern_matching_over_is_with_cast_check = true
91 | csharp_style_prefer_not_pattern = true
92 | csharp_style_prefer_pattern_matching = true
93 | csharp_style_prefer_switch_expression = true
94 |
95 | # Null-checking preferences
96 | csharp_style_conditional_delegate_call = true
97 |
98 | # Modifier preferences
99 | csharp_prefer_static_local_function = true
100 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
101 |
102 | # Code-block preferences
103 | csharp_prefer_braces = true
104 | csharp_prefer_simple_using_statement = true
105 |
106 | # Expression-level preferences
107 | csharp_prefer_simple_default_expression = true
108 | csharp_style_deconstructed_variable_declaration = true
109 | csharp_style_implicit_object_creation_when_type_is_apparent = true
110 | csharp_style_inlined_variable_declaration = true
111 | csharp_style_pattern_local_over_anonymous_function = true
112 | csharp_style_prefer_index_operator = true
113 | csharp_style_prefer_range_operator = true
114 | csharp_style_throw_expression = true
115 | csharp_style_unused_value_assignment_preference = discard_variable
116 | csharp_style_unused_value_expression_statement_preference = discard_variable
117 |
118 | # 'using' directive preferences
119 | csharp_using_directive_placement = outside_namespace
120 |
121 | #### C# Formatting Rules ####
122 |
123 | # New line preferences
124 | csharp_new_line_before_catch = true
125 | csharp_new_line_before_else = true
126 | csharp_new_line_before_finally = true
127 | csharp_new_line_before_members_in_anonymous_types = true
128 | csharp_new_line_before_members_in_object_initializers = true
129 | csharp_new_line_before_open_brace = anonymous_methods,anonymous_types,lambdas,methods,object_collection_array_initializers,properties,types
130 | csharp_new_line_between_query_expression_clauses = true
131 |
132 | # Indentation preferences
133 | csharp_indent_block_contents = true
134 | csharp_indent_braces = false
135 | csharp_indent_case_contents = true
136 | csharp_indent_case_contents_when_block = true
137 | csharp_indent_labels = one_less_than_current
138 | csharp_indent_switch_labels = true
139 |
140 | # Space preferences
141 | csharp_space_after_cast = false
142 | csharp_space_after_colon_in_inheritance_clause = true
143 | csharp_space_after_comma = true
144 | csharp_space_after_dot = false
145 | csharp_space_after_keywords_in_control_flow_statements = true
146 | csharp_space_after_semicolon_in_for_statement = true
147 | csharp_space_around_binary_operators = before_and_after
148 | csharp_space_around_declaration_statements = false
149 | csharp_space_before_colon_in_inheritance_clause = true
150 | csharp_space_before_comma = false
151 | csharp_space_before_dot = false
152 | csharp_space_before_open_square_brackets = false
153 | csharp_space_before_semicolon_in_for_statement = false
154 | csharp_space_between_empty_square_brackets = false
155 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
156 | csharp_space_between_method_call_name_and_opening_parenthesis = false
157 | csharp_space_between_method_call_parameter_list_parentheses = false
158 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
159 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
160 | csharp_space_between_method_declaration_parameter_list_parentheses = false
161 | csharp_space_between_parentheses = false
162 | csharp_space_between_square_brackets = false
163 |
164 | # Wrapping preferences
165 | csharp_preserve_single_line_blocks = true
166 | csharp_preserve_single_line_statements = true
167 |
168 | #### Naming styles ####
169 |
170 | # Naming rules
171 |
172 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
173 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
174 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
175 |
176 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
177 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types
178 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
179 |
180 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
181 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
182 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
183 |
184 | # Symbol specifications
185 |
186 | dotnet_naming_symbols.interface.applicable_kinds = interface
187 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
188 | dotnet_naming_symbols.interface.required_modifiers =
189 |
190 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
191 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
192 | dotnet_naming_symbols.types.required_modifiers =
193 |
194 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
195 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
196 | dotnet_naming_symbols.non_field_members.required_modifiers =
197 |
198 | # Naming styles
199 |
200 | dotnet_naming_style.pascal_case.required_prefix =
201 | dotnet_naming_style.pascal_case.required_suffix =
202 | dotnet_naming_style.pascal_case.word_separator =
203 | dotnet_naming_style.pascal_case.capitalization = pascal_case
204 |
205 | dotnet_naming_style.begins_with_i.required_prefix = I
206 | dotnet_naming_style.begins_with_i.required_suffix =
207 | dotnet_naming_style.begins_with_i.word_separator =
208 | dotnet_naming_style.begins_with_i.capitalization = pascal_case
--------------------------------------------------------------------------------
/src/CSharpx/CSharpx.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | netstandard2.0;net47
6 | Functional programming and other utilities for C#
7 | Functional programming and other utilities for C#
8 | 2.8.0-rc.2
9 | gsscoder
10 | Copyright © Giacomo Stelluti Scala, 2015-2021
11 | https://github.com/gsscoder/csharpx
12 | https://github.com/gsscoder/csharpx
13 | MIT
14 | functional;utility;api;library
15 | icon.png
16 | 8.0
17 |
18 |
19 | ../../artifacts/CSharpx/Debug
20 |
21 |
22 | ../../artifacts/CSharpx/Release
23 |
24 |
25 |
26 | True
27 |
28 |
29 |
30 |
31 |
32 |
33 | <_Parameter1>$(MSBuildProjectName).Specs
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CSharpx/CryptoRandom.cs:
--------------------------------------------------------------------------------
1 | //#define CSX_TYPES_INTERNAL // Uncomment or define at build time to set accessibility to internal.
2 |
3 | using System;
4 | using System.Diagnostics.CodeAnalysis;
5 | using System.Security.Cryptography;
6 |
7 | namespace CSharpx
8 | {
9 | /// A thread safe random number generator based on the RNGCryptoServiceProvider.
10 | #if !CSX_TYPES_INTERNAL
11 | public
12 | #endif
13 | class CryptoRandom : Random
14 | {
15 | readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
16 | byte[] _buffer;
17 | int _bufferPosition;
18 |
19 | /// Gets a value indicating whether this instance has random pool enabled.
20 | public bool IsRandomPoolEnabled { get; private set; }
21 |
22 | /// Initializes a new instance of the CryptoRandom class with. Using this
23 | /// overload will enable the random buffer pool.
24 | public CryptoRandom() : this(true) { }
25 |
26 | /// Initializes a new instance of the CryptoRandom class. This method will
27 | /// disregard whatever value is passed as seed and it's only implemented in order to be fully
28 | /// backwards compatible with System.Random. Using this overload will enable the random
29 | /// buffer pool.
30 | [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "ignoredSeed",
31 | Justification = "Cannot remove this parameter as we implement the full API of System.Random")]
32 | public CryptoRandom(int seed) : this(true) { }
33 |
34 | /// Initializes a new instance of the CryptoRandom class with optional random
35 | /// buffer.
36 | public CryptoRandom(bool enableRandomPool)
37 | {
38 | IsRandomPoolEnabled = enableRandomPool;
39 | }
40 |
41 | void InitBuffer()
42 | {
43 | if (IsRandomPoolEnabled) {
44 | if (_buffer == null || _buffer.Length != 512) {
45 | _buffer = new byte[512];
46 | }
47 | }
48 | else {
49 | if (_buffer == null || _buffer.Length != 4) {
50 | _buffer = new byte[4];
51 | }
52 | }
53 | _rng.GetBytes(_buffer);
54 | _bufferPosition = 0;
55 | }
56 |
57 | /// Returns a non-negative random integer.
58 | public override int Next() =>
59 | // Mask away the sign bit so that we always return nonnegative integers
60 | (int)GetRandomUInt32() & 0x7FFFFFFF;
61 |
62 | /// Returns a non-negative random integer that is less than the specified
63 | /// maximum.
64 | public override int Next(int maxValue)
65 | {
66 | if (maxValue < 0) throw new ArgumentOutOfRangeException(nameof(maxValue));
67 |
68 | return Next(0, maxValue);
69 | }
70 |
71 | /// Returns a non-negative random integer that is within a specified range.
72 | public override int Next(int minValue, int maxValue)
73 | {
74 | if (minValue > maxValue) throw new ArgumentOutOfRangeException(nameof(minValue));
75 | if (minValue == maxValue) return minValue;
76 |
77 | long diff = maxValue - minValue;
78 | while (true) {
79 | uint rand = GetRandomUInt32();
80 | long max = 1 + (long)uint.MaxValue;
81 | long remainder = max % diff;
82 | if (rand < max - remainder) {
83 | return (int)(minValue + (rand % diff));
84 | }
85 | }
86 | }
87 |
88 | /// Returns a random floating-point number that is greater than or equal to 0.0, and
89 | /// less than 1.0.
90 | public override double NextDouble() => GetRandomUInt32() / (1.0 + uint.MaxValue);
91 |
92 | /// Fills the elements of a specified array of bytes with random numbers.
93 | public override void NextBytes(byte[] buffer)
94 | {
95 | if (buffer == null) throw new ArgumentNullException(nameof(buffer));
96 |
97 | lock (this)
98 | {
99 | if (IsRandomPoolEnabled && _buffer == null) {
100 | InitBuffer();
101 | }
102 | // Can we fit the requested number of bytes in the buffer?
103 | if (IsRandomPoolEnabled && _buffer.Length <= buffer.Length)
104 | {
105 | int count = buffer.Length;
106 | EnsureRandomBuffer(count);
107 | Buffer.BlockCopy(_buffer, _bufferPosition, buffer, 0, count);
108 | _bufferPosition += count;
109 | }
110 | else {
111 | // Draw bytes directly from the RNGCryptoProvider
112 | _rng.GetBytes(buffer);
113 | }
114 | }
115 | }
116 |
117 | uint GetRandomUInt32()
118 | {
119 | lock (this) {
120 | EnsureRandomBuffer(4);
121 | uint rand = BitConverter.ToUInt32(_buffer, _bufferPosition);
122 | _bufferPosition += 4;
123 | return rand;
124 | }
125 | }
126 |
127 | void EnsureRandomBuffer(int requiredBytes)
128 | {
129 | if (_buffer == null) {
130 | InitBuffer();
131 | }
132 |
133 | if (requiredBytes > _buffer.Length) throw new ArgumentOutOfRangeException(nameof(requiredBytes),
134 | "Cannot be greater than random buffer.");
135 |
136 | if ((_buffer.Length - _bufferPosition) < requiredBytes) {
137 | InitBuffer();
138 | }
139 | }
140 | }
141 | }
--------------------------------------------------------------------------------
/src/CSharpx/Either.cs:
--------------------------------------------------------------------------------
1 | //reguires: Unit.cs, Maybe.cs
2 | //#define CSX_TYPES_INTERNAL // Uncomment or define at build time to set accessibility to internal.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace CSharpx
8 | {
9 | #region Either Type
10 | /// Discriminator for Either.
11 | #if !CSX_TYPES_INTERNAL
12 | public
13 | #endif
14 | enum EitherType
15 | {
16 | /// Failed computation case.
17 | Left,
18 | /// Sccessful computation case.
19 | Right
20 | }
21 |
22 | #if !CSX_TYPES_INTERNAL
23 | public
24 | #endif
25 | /// The Either type represents values with two possibilities: a value of type
26 | /// Either T U is either Left T or Right U. The Either type is
27 | /// sometimes used to represent a value which is either correct or an error; by convention, the
28 | /// Left constructor is used to hold an error value and the Right constructor is
29 | /// used to hold a correct value (mnemonic: "right" also means "correct").
30 | struct Either
31 | {
32 | readonly TLeft _leftValue;
33 | readonly TRight _rightValue;
34 |
35 | internal Either(TLeft value)
36 | {
37 | _leftValue = value;
38 | _rightValue = default;
39 | Tag = EitherType.Left;
40 | }
41 |
42 | internal Either(TRight value)
43 | {
44 | _leftValue = default;
45 | _rightValue = value;
46 | Tag = EitherType.Right;
47 | }
48 |
49 | public EitherType Tag { get; private set; }
50 |
51 | #region Basic Match Methods
52 | /// Matches a Left value returning true and value itself via an output
53 | /// parameter.
54 | public bool MatchLeft(out TLeft value)
55 | {
56 | value = Tag == EitherType.Left ? _leftValue : default;
57 | return Tag == EitherType.Left;
58 | }
59 |
60 | /// Matches a Right value returning true and value itself via an output
61 | /// parameter.
62 | public bool MatchRight(out TRight value)
63 | {
64 | value = Tag == EitherType.Right ? _rightValue : default;
65 | return Tag == EitherType.Right;
66 | }
67 | #endregion
68 | }
69 |
70 | #if !CSX_TYPES_INTERNAL
71 | public
72 | #endif
73 | static class Either
74 | {
75 | #region Value Case Constructors
76 | /// Builds the Left case of an Either value.
77 | public static Either Left(TLeft value) =>
78 | new Either(value);
79 |
80 | /// Builds the Right case of an Either value.
81 | public static Either Right(TRight value) =>
82 | new Either(value);
83 | #endregion
84 |
85 | #region Monad
86 | /// Inject a value into the Either type, returning Right case.
87 | public static Either Return(TRight value) =>
88 | Either.Right(value);
89 |
90 | /// Monadic bind.
91 | public static Either Bind(
92 | Either either, Func> func)
93 | {
94 | if (func == null) throw new ArgumentNullException(nameof(func));
95 |
96 | if (either.MatchRight(out TRight right)) {
97 | return func(right);
98 | }
99 | return Either.Left(either.GetLeft());
100 | }
101 | #endregion
102 |
103 | #region Functor
104 | /// Transforms a Either right value by using a specified mapping function.
105 | public static Either Map(Either either,
106 | Func func)
107 | {
108 | if (func == null) throw new ArgumentNullException(nameof(func));
109 |
110 | if (either.MatchRight(out TRight right)) {
111 | return Either.Right(func(right));
112 | }
113 | return Either.Left(either.GetLeft());
114 | }
115 | #endregion
116 |
117 | #region Bifunctor
118 | /// Maps both parts of a Either type. Applies the first function if Either
119 | /// is Left. Otherwise applies the second function.
120 | public static Either Bimap(Either either,
121 | Func mapLeft, Func mapRight)
122 | {
123 | if (mapLeft == null) throw new ArgumentNullException(nameof(mapLeft));
124 | if (mapRight == null) throw new ArgumentNullException(nameof(mapRight));
125 |
126 | if (either.MatchRight(out TRight right)) {
127 | return Either.Right(mapRight(right));
128 | }
129 | return Either.Left(mapLeft(either.GetLeft()));
130 | }
131 | #endregion
132 |
133 | /// Fail with a message. Not part of mathematical definition of a monad.
134 | public static Either Fail(string message) => throw new Exception(message);
135 |
136 | /// Wraps a function, encapsulates any exception thrown within to a Either.
137 | public static Either Try(Func func)
138 | {
139 | if (func == null) throw new ArgumentNullException(nameof(func));
140 |
141 | try {
142 | return new Either(func());
143 | }
144 | catch (Exception ex) {
145 | return new Either(ex);
146 | }
147 | }
148 |
149 | /// Attempts to cast an object. Stores the cast value in Right if successful, otherwise
150 | /// stores the exception in Left.
151 | public static Either Cast(object obj) => Either.Try(() => (TRight)obj);
152 |
153 | /// Converts a Just value to a Right and a Nothing value to a
154 | /// Left.
155 | public static Either FromMaybe(Maybe maybe, TLeft left)
156 | {
157 | if (maybe.Tag == MaybeType.Just) {
158 | return Either.Right(maybe.FromJust());
159 | }
160 | return Either.Left(left);
161 | }
162 |
163 | static TLeft GetLeft(this Either either) => either.FromLeft();
164 | }
165 |
166 | #if !CSX_TYPES_INTERNAL
167 | public
168 | #endif
169 | static class EitherExtensions
170 | {
171 | #region LINQ Operators
172 | /// Map operation compatible with LINQ.
173 | public static Either Select(
174 | this Either either,
175 | Func selector) => Either.Map(either, selector);
176 |
177 | /// Map operation compatible with LINQ.
178 | public static Either SelectMany(this Either result,
179 | Func> func) => Either.Bind(result, func);
180 | #endregion
181 |
182 | #region Alternative Match Method
183 | public static Unit Match(this Either either,
184 | Func onLeft, Func onRight)
185 | {
186 | if (onLeft == null) throw new ArgumentNullException(nameof(onLeft));
187 | if (onRight == null) throw new ArgumentNullException(nameof(onRight));
188 |
189 | return either.MatchRight(out TRight right) switch {
190 | true => onRight(right),
191 | _ => onLeft(either.FromLeft())
192 | };
193 | }
194 | #endregion
195 |
196 | /// Equivalent to monadic Return operation. Builds a Right value
197 | /// by default.
198 | public static Either ToEither(this TRight value) => Either.Return(value);
199 |
200 | /// Equivalent to monadic Bind.
201 | public static Either Bind(
202 | this Either either,
203 | Func> func) => Either.Bind(either, func);
204 |
205 | /// Equivalent to monadic Map.
206 | public static Either Map(
207 | this Either either,
208 | Func func) => Either.Map(either, func);
209 |
210 | /// Eviqualent to monadic Bimap.
211 | public static Either Bimap(
212 | this Either either,
213 | Func mapLeft,
214 | Func mapRight) => Either.Bimap(either, mapLeft, mapRight);
215 |
216 | /// Returns true if it is in form of Left.
217 | public static bool IsLeft(this Either either) =>
218 | either.Tag == EitherType.Left;
219 |
220 | /// Returns true if it is in form of Right.
221 | public static bool IsRight(this Either either) =>
222 | either.Tag == EitherType.Right;
223 |
224 | /// Extracts the element out of Left and returns a default value (or noneValue
225 | /// when given) if it is in form of Right.
226 | public static TLeft FromLeft(this Either either,
227 | TLeft noneValue = default) => either.MatchLeft(out TLeft value) ? value : noneValue;
228 |
229 | /// Extracts the element out of Left and throws an exception if it is form of
230 | /// Right.
231 | public static TLeft FromLeftOrFail(this Either either,
232 | Exception exceptionToThrow = null)
233 | {
234 | if (either.MatchLeft(out TLeft value)) {
235 | return value;
236 | }
237 | throw exceptionToThrow ?? new Exception("The value is empty.");
238 | }
239 |
240 | /// Extracts the element out of Left and returns a default (or noneValue
241 | /// when given) value if it is in form ofRight.
242 | public static TRight FromRight(this Either either,
243 | TRight noneValue = default) => either.MatchRight(out TRight value) ? value : noneValue;
244 |
245 | /// Extracts the element out of Left and throws an exception if it is form of
246 | /// Right.
247 | public static TRight FromRightOrFail(this Either either,
248 | Exception exceptionToThrow = null)
249 | {
250 | if (either.MatchRight(out TRight value)) {
251 | return value;
252 | }
253 | throw exceptionToThrow ?? new Exception("The value is empty.");
254 | }
255 |
256 | #region IEnumerable
257 | /// Extracts from a sequence of Either all the Left elements. All the
258 | /// Left elements are extracted in order.
259 | public static IEnumerable Lefts(this IEnumerable> source)
260 | {
261 | if (source == null) throw new ArgumentNullException(nameof(source));
262 |
263 | return _(); IEnumerable _()
264 | {
265 | foreach (var either in source) {
266 | if (either.Tag == EitherType.Left) yield return either.FromLeft();
267 | }
268 | }
269 | }
270 |
271 | /// Extracts from a sequence of Either all the Right elements. All the
272 | /// Rights elements are extracted in order.
273 | public static IEnumerable Rights(this IEnumerable> source)
274 | {
275 | if (source == null) throw new ArgumentNullException(nameof(source));
276 |
277 | return _(); IEnumerable _()
278 | {
279 | foreach (var either in source) {
280 | if (either.Tag == EitherType.Right) yield return either.FromRight();
281 | }
282 | }
283 | }
284 |
285 | /// Partitions a sequence of Either into two sequences. All the Left
286 | /// elements are extracted, in order, to the first component of the pair. Similarly the Right
287 | /// elements are extracted to the second component of the pair.
288 | public static (IEnumerable, IEnumerable) Partition(
289 | this IEnumerable> source)
290 | {
291 | if (source == null) throw new ArgumentNullException(nameof(source));
292 |
293 | var lefts = new List();
294 | var rights = new List();
295 |
296 | foreach (var either in source) {
297 | if (either.Tag == EitherType.Left) lefts.Add(either.FromLeft());
298 | else rights.Add(either.FromRight());
299 | }
300 | return (lefts, rights);
301 | }
302 | #endregion
303 | }
304 | #endregion
305 | }
--------------------------------------------------------------------------------
/src/CSharpx/EnumerableExtensions.cs:
--------------------------------------------------------------------------------
1 | //requires: Unit.cs, Either.cs, CryptoRandom.cs
2 | //#define CSX_TYPES_INTERNAL // Uncomment or define at build time to set accessibility to internal.
3 |
4 | using System;
5 | using System.Collections;
6 | using System.Collections.Generic;
7 | using System.Globalization;
8 | using System.Linq;
9 | using System.Text;
10 | using LinqEnumerable = System.Linq.Enumerable;
11 |
12 | namespace CSharpx
13 | {
14 | #if !CSX_TYPES_INTERNAL
15 | public
16 | #endif
17 | static class EnumerableExtensions
18 | {
19 | #region Internal
20 | static IEnumerable AssertCountImpl(IEnumerable source,
21 | int count, Func errorSelector)
22 | {
23 | var collection = source as ICollection; // Optimization for collections
24 | if (collection != null) {
25 | if (collection.Count != count) {
26 | throw errorSelector(collection.Count.CompareTo(count), count);
27 | }
28 | return source;
29 | }
30 | return ExpectingCountYieldingImpl(source, count, errorSelector);
31 | }
32 |
33 | static IEnumerable ExpectingCountYieldingImpl(IEnumerable source,
34 | int count, Func errorSelector)
35 | {
36 | var iterations = 0;
37 | foreach (var element in source) {
38 | iterations++;
39 | if (iterations > count) {
40 | throw errorSelector(1, count);
41 | }
42 | yield return element;
43 | }
44 | if (iterations != count) {
45 | throw errorSelector(-1, count);
46 | }
47 | }
48 | #endregion
49 |
50 | /// Returns the cartesian product of two sequences by combining each element of the
51 | /// first set with each in the second and applying the user=define projection to the
52 | /// pair.
53 | public static IEnumerable Cartesian(this IEnumerable first, IEnumerable second, Func resultSelector)
54 | {
55 | if (first == null) throw new ArgumentNullException(nameof(first));
56 | if (second == null) throw new ArgumentNullException(nameof(second));
57 | if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
58 |
59 | return from element1 in first
60 | from element2 in second // TODO buffer to avoid multiple enumerations
61 | select resultSelector(element1, element2);
62 | }
63 |
64 | /// Prepends a single value to a sequence.
65 | public static IEnumerable Prepend(this IEnumerable source, TSource value)
66 | {
67 | if (source == null) throw new ArgumentNullException(nameof(source));
68 |
69 | return LinqEnumerable.Concat(LinqEnumerable.Repeat(value, 1), source);
70 | }
71 |
72 | #region Concat
73 | /// Returns a sequence consisting of the head element and the given tail
74 | /// elements.
75 | public static IEnumerable Concat(this T head, IEnumerable tail)
76 | {
77 | if (tail == null) throw new ArgumentNullException(nameof(tail));
78 |
79 | return tail.Prepend(head);
80 | }
81 |
82 | /// Returns a sequence consisting of the head elements and the given tail element.
83 | ///
84 | public static IEnumerable Concat(this IEnumerable head, T tail)
85 | {
86 | if (head == null) throw new ArgumentNullException(nameof(head));
87 |
88 | return LinqEnumerable.Concat(head, LinqEnumerable.Repeat(tail, 1));
89 | }
90 | #endregion
91 |
92 | #region Exclude
93 | /// Excludes elements from a sequence starting at a given
94 | /// index.
95 | public static IEnumerable Exclude(this IEnumerable source, int startIndex, int count)
96 | {
97 | if (source == null) throw new ArgumentNullException(nameof(source));
98 | if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex));
99 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
100 |
101 | return ExcludeImpl(source, startIndex, count);
102 | }
103 |
104 | static IEnumerable ExcludeImpl(IEnumerable source, int startIndex, int count)
105 | {
106 | var index = -1;
107 | var endIndex = startIndex + count;
108 | using var iter = source.GetEnumerator();
109 | // yield the first part of the sequence
110 | while (iter.MoveNext() && ++index < startIndex) {
111 | yield return iter.Current;
112 | }
113 | // skip the next part (up to count elements)
114 | while (++index < endIndex && iter.MoveNext()) {
115 | continue;
116 | }
117 | // yield the remainder of the sequence
118 | while (iter.MoveNext()) {
119 | yield return iter.Current;
120 | }
121 | }
122 | #endregion
123 |
124 | #region Index
125 | /// Returns a sequence of KeyValuePair where the key is the zero-based index
126 | /// of the value in the source sequence.
127 | public static IEnumerable> Index(
128 | this IEnumerable source) => source.Index(0);
129 |
130 | /// Returns a sequence of KeyValuePair where the key is the index of the value
131 | /// in the source sequence. An additional parameter specifies the starting index.
132 | public static IEnumerable> Index(
133 | this IEnumerable source, int startIndex) => source.Select((element, index) =>
134 | new KeyValuePair(startIndex + index, element));
135 | #endregion
136 |
137 | #region Fold
138 | /// Returns the result of applying a function to a sequence of 1 element.
139 | public static TResult Fold(this IEnumerable source,
140 | Func folder) => FoldImpl(source, 1, folder, null, null, null);
141 |
142 | /// Returns the result of applying a function to a sequence of 2 elements.
143 | public static TResult Fold(this IEnumerable source,
144 | Func folder) => FoldImpl(source, 2, null, folder, null, null);
145 |
146 | /// Returns the result of applying a function to a sequence of 3 elements.
147 | public static TResult Fold(this IEnumerable source,
148 | Func folder) => FoldImpl(source, 3, null, null, folder, null);
149 |
150 | /// Returns the result of applying a function to a sequence of 4 elements.
151 | public static TResult Fold(this IEnumerable source,
152 | Func folder) => FoldImpl(source, 4, null, null, null, folder);
153 |
154 | static TResult FoldImpl(IEnumerable source, int count,
155 | Func folder1,
156 | Func folder2,
157 | Func folder3,
158 | Func folder4)
159 | {
160 | if (source == null) throw new ArgumentNullException(nameof(source));
161 | if (count == 1 && folder1 == null
162 | || count == 2 && folder2 == null
163 | || count == 3 && folder3 == null
164 | || count == 4 && folder4 == null)
165 | { // ReSharper disable NotResolvedInText
166 | throw new ArgumentNullException("folder"); // ReSharper restore NotResolvedInText
167 | }
168 |
169 | var elements = new T[count];
170 | foreach (var e in AssertCountImpl(
171 | source.Index(), count, OnFolderSourceSizeErrorSelector)) {
172 | elements[e.Key] = e.Value;
173 | }
174 |
175 | return count switch
176 | {
177 | 1 => folder1(elements[0]),
178 | 2 => folder2(elements[0], elements[1]),
179 | 3 => folder3(elements[0], elements[1], elements[2]),
180 | 4 => folder4(elements[0], elements[1], elements[2], elements[3]),
181 | _ => throw new NotSupportedException(),
182 | };
183 | }
184 |
185 | static readonly Func OnFolderSourceSizeErrorSelector = OnFolderSourceSizeError;
186 |
187 | static Exception OnFolderSourceSizeError(int cmp, int count)
188 | {
189 | var message = cmp < 0
190 | ? "Sequence contains too few elements when exactly {0} {1} expected."
191 | : "Sequence contains too many elements when exactly {0} {1} expected.";
192 | return new Exception(string.Format(message, count.ToString("N0"), count == 1 ? "was" : "were"));
193 | }
194 | #endregion
195 |
196 | #region Pairwise
197 | /// Returns a sequence resulting from applying a function to each element in the
198 | /// source sequence and its predecessor, with the exception of the first element which is
199 | /// only returned as the predecessor of the second element.
200 | public static IEnumerable Pairwise(this IEnumerable source, Func resultSelector)
201 | {
202 | if (source == null) throw new ArgumentNullException(nameof(source));
203 | if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
204 |
205 | return PairwiseImpl(source, resultSelector);
206 | }
207 |
208 | static IEnumerable PairwiseImpl(this IEnumerable source, Func resultSelector)
209 | {
210 | using var e = source.GetEnumerator();
211 | if (!e.MoveNext()) {
212 | yield break;
213 | }
214 | var previous = e.Current;
215 | while (e.MoveNext()) {
216 | yield return resultSelector(previous, e.Current);
217 | previous = e.Current;
218 | }
219 | }
220 | #endregion
221 |
222 | # region ToDelimitedString
223 | /// Creates a delimited string from a sequence of values. The delimiter used depends
224 | /// on the current culture of the executing thread.
225 | public static string ToDelimitedString(
226 | this IEnumerable source) => ToDelimitedString(source, null);
227 |
228 | /// Creates a delimited string from a sequence of values and
229 | /// a given delimiter.
230 | public static string ToDelimitedString(
231 | this IEnumerable source, string delimiter)
232 | {
233 | if (source == null) throw new ArgumentNullException(nameof(source));
234 |
235 | return ToDelimitedStringImpl(source, delimiter, (sb, e) => sb.Append(e));
236 | }
237 |
238 | static string ToDelimitedStringImpl(IEnumerable source, string delimiter,
239 | Func append)
240 | {
241 | delimiter = delimiter ?? CultureInfo.CurrentCulture.TextInfo.ListSeparator;
242 | var builder = new StringBuilder();
243 | var iterations = 0;
244 | foreach (var value in source) {
245 | if (iterations++ > 0) builder.Append(delimiter);
246 | append(builder, value);
247 | }
248 | return builder.ToString();
249 | }
250 | #endregion
251 |
252 | #region DistinctBy
253 | /// Returns all distinct elements of the given source, where "distinctness"
254 | /// is determined via a projection and the default equality comparer for the projected
255 | /// type.
256 | public static IEnumerable DistinctBy(this IEnumerable source,
257 | Func keySelector)
258 | {
259 | if (source == null) throw new ArgumentNullException(nameof(source));
260 | if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
261 |
262 | return source.DistinctBy(keySelector, null);
263 | }
264 |
265 | /// Returns all distinct elements of the given source, where "distinctness"
266 | /// is determined via a projection and the specified comparer for the projected type.
267 | public static IEnumerable DistinctBy(this IEnumerable source,
268 | Func keySelector, IEqualityComparer comparer)
269 | {
270 | if (source == null) throw new ArgumentNullException(nameof(source));
271 | if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
272 |
273 | return _(); IEnumerable _()
274 | {
275 | var knownKeys = new HashSet(comparer);
276 | foreach (var element in source) {
277 | if (knownKeys.Add(keySelector(element)))
278 | yield return element;
279 | }
280 | }
281 | }
282 | #endregion
283 |
284 | #region Repeat
285 | /// Repeats the sequence the specified number of times.
286 | public static IEnumerable Repeat(this IEnumerable source, int count)
287 | {
288 | if (source == null) throw new ArgumentNullException(nameof(source));
289 | if (count < 0) throw new ArgumentOutOfRangeException(nameof(count),
290 | "Repeat count must be greater than or equal to zero.");
291 |
292 | return RepeatImpl(source, count);
293 | }
294 |
295 | /// Repeats the sequence forever.
296 | public static IEnumerable Repeat(this IEnumerable source)
297 | {
298 | if (source == null) throw new ArgumentNullException(nameof(source));
299 |
300 | return RepeatImpl(source, null);
301 | }
302 |
303 | static IEnumerable RepeatImpl(IEnumerable source, int? count)
304 | {
305 | var memo = source.Materialize();
306 | using (memo as IDisposable) {
307 | while (count == null || count-- > 0) {
308 | foreach (var item in memo)
309 | yield return item;
310 | }
311 | }
312 | }
313 | #endregion
314 |
315 | /// Safe function that returns Just(first element) or Nothing.
316 | public static Maybe TryHead(this IEnumerable source)
317 | {
318 | if (source == null) throw new ArgumentNullException(nameof(source));
319 |
320 | using var e = source.GetEnumerator(); return e.MoveNext()
321 | ? Maybe.Just(e.Current)
322 | : Maybe.Nothing();
323 | }
324 |
325 | /// Safe function that returns Just(last element) or Nothing.
326 | public static Maybe TryLast(this IEnumerable source)
327 | {
328 | if (source == null) throw new ArgumentNullException(nameof(source));
329 |
330 | using var e = source.GetEnumerator();
331 | if (!e.MoveNext()) return Maybe.Nothing();
332 | T result = e.Current;
333 | while (e.MoveNext()) result = e.Current;
334 | return Maybe.Just(result);
335 | }
336 |
337 | /// Turns an empty sequence to Nothing, otherwise Just(sequence).
338 | public static Maybe> ToMaybe(this IEnumerable source)
339 | {
340 | if (source == null) throw new ArgumentNullException(nameof(source));
341 |
342 | using var e = source.GetEnumerator();
343 | return e.MoveNext()
344 | ? Maybe.Just(source)
345 | : Maybe.Nothing>();
346 | }
347 |
348 | /// Applies a function to each element of the source sequence and returns a new
349 | /// sequence of elements where the function returns Just(value).
350 | public static IEnumerable Choose(this IEnumerable source,
351 | Func> chooser)
352 | {
353 | if (source == null) throw new ArgumentNullException(nameof(source));
354 | if (chooser == null) throw new ArgumentNullException(nameof(chooser));
355 |
356 | return _(); IEnumerable _()
357 | {
358 | foreach (var item in source) {
359 | var result = chooser(item);
360 | if (result.MatchJust(out TResult value)) {
361 | yield return value;
362 | }
363 | }
364 | }
365 | }
366 |
367 | /// Returns the first element of a sequence as Just, or Nothing if the sequence
368 | /// contains no elements.
369 | public static Maybe FirstOrNothing(this IEnumerable source) {
370 | if (source == null) throw new ArgumentNullException(nameof(source));
371 |
372 | if (source is IList list) {
373 | if (list.Count > 0) return Maybe.Just(list[0]);
374 | }
375 | else {
376 | using IEnumerator e = source.GetEnumerator();
377 | if (e.MoveNext()) return Maybe.Just(e.Current);
378 | }
379 | return Maybe.Nothing();
380 | }
381 |
382 | /// Returns the first element of the sequence as Just that satisfies a condition or
383 | /// Nothing if no such element is found.
384 | public static Maybe FirstOrNothing(this IEnumerable source,
385 | Func predicate) {
386 | if (source == null) throw new ArgumentNullException(nameof(source));
387 | if (predicate == null) throw new ArgumentNullException(nameof(predicate));
388 |
389 | foreach (TSource element in source) {
390 | if (predicate(element)) return Maybe.Just(element);
391 | }
392 | return Maybe.Nothing();
393 | }
394 |
395 | /// Returns the last element of a sequence as Just, or Nothing if the sequence
396 | /// contains no elements.
397 | public static Maybe LastOrNothing(this IEnumerable source)
398 | {
399 | if (source == null) throw new ArgumentNullException(nameof(source));
400 |
401 | if (source is IList list) {
402 | int count = list.Count;
403 | if (count > 0) return Maybe.Just(list[count - 1]);
404 | }
405 | else {
406 | using IEnumerator e = source.GetEnumerator();
407 | if (e.MoveNext()) {
408 | TSource result;
409 | do {
410 | result = e.Current;
411 | } while (e.MoveNext());
412 | return Maybe.Just(result);
413 | }
414 | }
415 | return Maybe.Nothing();
416 | }
417 |
418 | /// Returns the last element of a sequence as Just that satisfies a condition or Nothing if
419 | /// no such element is found.
420 | public static Maybe LastOrNothing(this IEnumerable source, Func predicate) {
421 | if (source == null) throw new ArgumentNullException(nameof(source));
422 | if (predicate == null) throw new ArgumentNullException(nameof(predicate));
423 |
424 | var result = Maybe.Nothing();
425 | foreach (var element in source) {
426 | if (predicate(element)) {
427 | result = Maybe.Just(element);
428 | }
429 | }
430 | return result;
431 | }
432 |
433 | /// Returns the only element of a sequence as Just, or Nothing if the sequence is
434 | /// empty.
435 | public static Maybe SingleOrNothing(this IEnumerable source) {
436 | if (source == null) throw new ArgumentNullException(nameof(source));
437 |
438 | if (source is IList list) {
439 | switch (list.Count) {
440 | case 0: return Maybe.Nothing();
441 | case 1: return Maybe.Just(list[0]);
442 | }
443 | }
444 | else {
445 | using IEnumerator e = source.GetEnumerator();
446 | if (!e.MoveNext()) return Maybe.Nothing();
447 | TSource result = e.Current;
448 | if (!e.MoveNext()) return Maybe.Just(result);
449 | }
450 | return Maybe.Nothing();
451 | }
452 |
453 | /// Returns the only element of a sequence that satisfies a specified condition as
454 | /// Just or a Nothing if no such element exists; this method throws an exception if more than
455 | /// one element satisfies the condition.
456 | public static Maybe SingleOrNothing(this IEnumerable source, Func predicate) {
457 | if (source == null) throw new ArgumentNullException(nameof(source));
458 | if (predicate == null) throw new ArgumentNullException(nameof(predicate));
459 |
460 | var result = Maybe.Nothing();
461 | var count = 0L;
462 | foreach (var element in source) {
463 | if (predicate(element)) {
464 | result = Maybe.Just(element);
465 | checked { count++; }
466 | }
467 | }
468 | return count switch
469 | {
470 | 0 => Maybe.Nothing(),
471 | 1 => result,
472 | _ => throw new InvalidOperationException("Sequence contains more than one element"),
473 | };
474 | }
475 |
476 | /// Returns the element at a specified index in a sequence as Just or Nothing
477 | /// if the index is out of range.
478 | public static Maybe ElementAtOrNothing(this IEnumerable source, int index) {
479 | if (source == null) throw new ArgumentNullException(nameof(source));
480 |
481 | if (index >= 0) {
482 | if (source is IList list) {
483 | if (index < list.Count) return Maybe.Just(list[index]);
484 | }
485 | else {
486 | using IEnumerator e = source.GetEnumerator();
487 | while (true) {
488 | if (!e.MoveNext()) break;
489 | if (index == 0) return Maybe.Just(e.Current);
490 | index--;
491 | }
492 | }
493 | }
494 | return Maybe.Nothing();
495 | }
496 |
497 | /// Immediately executes the given action on each element in the source sequence.
498 | public static Unit ForEach(this IEnumerable source, Action action)
499 | {
500 | if (source == null) throw new ArgumentNullException(nameof(source));
501 | if (action == null) throw new ArgumentNullException(nameof(action));
502 |
503 | foreach (var element in source) {
504 | action(element);
505 | }
506 | return Unit.Default;
507 | }
508 |
509 | /// Return everything except first element and throws exception if empty.
510 | public static IEnumerable Tail(this IEnumerable source)
511 | {
512 | if (source == null) throw new ArgumentNullException(nameof(source));
513 |
514 | return _(); IEnumerable