-
Notifications
You must be signed in to change notification settings - Fork 74
Expand file tree
/
Copy pathExtensions.fs
More file actions
187 lines (162 loc) · 7.17 KB
/
Copy pathExtensions.fs
File metadata and controls
187 lines (162 loc) · 7.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// The MIT License (MIT)
// Copyright (c) 2016 Bazinga Technologies Inc
module internal FSharp.Data.GraphQL.Extensions
open System.Reflection
open System.Collections.Generic
open System.Text.Json.Serialization
type IDictionary<'TKey, 'TValue> with
member x.TryFind(key : 'TKey) =
match x.TryGetValue(key) with
| (true, value) -> Some value
| _ -> None
type TypeInfo with
/// If no property is found with the specified name, it will try changing the case of the first letter
member x.GetDeclaredProperty(propertyName: string, ignoreCase: bool) =
match x.GetDeclaredProperty(propertyName), ignoreCase with
| null, true ->
let first =
let first = propertyName.Substring(0,1)
match first.ToUpper() with
| upper when upper <> first -> upper
| _ -> first.ToLower()
x.GetDeclaredProperty(first + propertyName.Substring(1))
| prop, _ -> prop
/// If no method is found with the specified name, it will try changing the case of the first letter
member x.GetDeclaredMethod(propertyName: string, ignoreCase: bool) =
match x.GetDeclaredMethod(propertyName), ignoreCase with
| null, true ->
let first =
let first = propertyName.Substring(0,1)
match first.ToUpper() with
| upper when upper <> first -> upper
| _ -> first.ToLower()
x.GetDeclaredMethod(first + propertyName.Substring(1))
| prop, _ -> prop
module Option =
let mergeWith (f: 'T -> 'T -> 'T) (o1 : 'T option) (o2 : 'T option) : 'T option =
match (o1, o2) with
| Some a, Some b -> Some (f a b)
| Some a, _ -> Some a
| _, Some b -> Some b
| _, _ -> None
let unwrap (defaultValue : 'U) (onSome : 'T -> 'U) (o : 'T option) : 'U =
match o with
| Some t -> onSome t
| None -> defaultValue
module Skippable =
let ofList list =
match list with
| [] -> Skip
| list -> Include list
module Dictionary =
let addWith (f : 'V -> 'V -> 'V) (key : 'K) (value : 'V) (dict : Dictionary<'K, 'V>) : unit =
match dict.TryGetValue(key) with
| true, v -> dict.[key] <- f value v
| false, _ -> dict.Add(key, value)
module Array =
/// <summary>
/// Returns a new array with unique elements. Uniqueness is determined by
/// output of the <paramref name="keyf"/> function.
/// </summary>
/// <param name="keyf">Function, which output is used to determine uniqueness of input elements.</param>
/// <param name="array">Array of elements.</param>
let distinctBy keyf (array:'T[]) =
let temp = Array.zeroCreate array.Length
let mutable i = 0
let hashSet = HashSet<_>(HashIdentity.Structural<_>)
for v in array do
if hashSet.Add(keyf v) then
temp.[i] <- v
i <- i + 1
Array.sub temp 0 i
/// <summary>
/// Attempts to find the first element in an array that satisfies the given predicate.
/// </summary>
/// <param name="predicate">Function to test each element.</param>
/// <param name="source">The input array.</param>
/// <returns>ValueSome of the first matching element, or ValueNone if no match is found.</returns>
let vtryFind predicate (source : 'T array) =
let mutable result = ValueNone
let mutable i = 0
while i < source.Length && result.IsNone do
if predicate source[i] then
result <- ValueSome source[i]
i <- i + 1
result
/// <summary>
/// Applies a function to each element of an array and returns the first result where the function returns ValueSome.
/// </summary>
/// <param name="mapping">Function to apply to each element.</param>
/// <param name="source">The input array.</param>
/// <returns>ValueSome of the first successful mapping result, or ValueNone if no match is found.</returns>
let vtryPick mapping (source : 'T array) =
let mutable result = ValueNone
let mutable i = 0
while i < source.Length && result.IsNone do
result <- mapping source[i]
i <- i + 1
result
module List =
/// <summary>
/// Merges elements of two lists, returning a new list without duplicates.
/// </summary>
/// <param name="f">Function used to determine if any two given elements are considered equal.</param>
/// <param name="listx">First list with elements to merge.</param>
/// <param name="listy">Second list with elements to merge.</param>
let mergeBy f listx listy =
let uniqx =
listx
|> List.filter (fun x -> not <| List.exists(fun y -> f(x) = f(y)) listy)
uniqx @ listy
/// <summary>
/// Attempts to find the first element in a list that satisfies the given predicate.
/// </summary>
/// <param name="predicate">Function to test each element.</param>
/// <param name="source">The input list.</param>
/// <returns>ValueSome of the first matching element, or ValueNone if no match is found.</returns>
let rec vtryFind predicate (source : 'T list) =
match source with
| [] -> ValueNone
| head :: tail ->
if predicate head then
ValueSome head
else
vtryFind predicate tail
/// <summary>
/// Applies a function to each element of a list and returns the first result where the function returns ValueSome.
/// </summary>
/// <param name="mapping">Function to apply to each element.</param>
/// <param name="source">The input list.</param>
/// <returns>ValueSome of the first successful mapping result, or ValueNone if no match is found.</returns>
let rec vtryPick mapping (source : 'T list) =
match source with
| [] -> ValueNone
| head :: tail ->
match mapping head with
| ValueSome result -> ValueSome result
| ValueNone -> vtryPick mapping tail
module Set =
/// <summary>
/// Maps over each of the <paramref name="set"/> elements, applying function
/// over each one of them to generate new Set. Sets generated this way are
/// then flattened into single output set.
/// </summary>
/// <param name="f">Function used to generate Set from each of the input's elements.</param>
/// <param name="set">Input set.</param>
let collect f set = set |> Set.fold (fun acc e -> acc + f e) Set.empty
module Map =
/// <summary>
/// Merges the entries of two maps by their key, returning new map in result.
/// </summary>
/// <param name="mergeFn">
/// Function, which takes key shared by entries in both maps, first entry's value,
/// second entry's value to produce a result value used in newly generated map.
/// </param>
/// <param name="mapx">First map with elements to merge.</param>
/// <param name="mapy">Second map with elements to merge.</param>
let merge mergeFn mapx mapy =
mapy
|> Map.fold (fun acc ky vy ->
match Map.tryFind ky acc with
| Some vx -> Map.add ky (mergeFn ky vx vy) acc
| None -> Map.add ky vy acc) mapx