-
-
Notifications
You must be signed in to change notification settings - Fork 159
/
Copy pathExtensions.cs
241 lines (197 loc) · 5.94 KB
/
Extensions.cs
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// ReSharper disable UnusedVariable
static class Extensions
{
static HashSet<Type> numericTypes =
[
typeof(int),
typeof(double),
typeof(decimal),
typeof(long),
typeof(short),
typeof(sbyte),
typeof(byte),
typeof(ulong),
typeof(ushort),
typeof(uint),
typeof(float)
];
public static bool IsNumeric(this Type type) =>
numericTypes.Contains(Nullable.GetUnderlyingType(type) ?? type);
public static string Extension(this FileStream file) =>
Path.GetExtension(file.Name)[1..];
public static bool ContainsNewline(this CharSpan span) =>
span.IndexOfAny('\r', '\n') != -1;
public static Version MajorMinor(this Version version) =>
new(version.Major, version.Minor);
public static async Task<List<T>> ToList<T>(this IAsyncEnumerable<T> target)
{
var list = new List<T>();
await foreach (var item in target)
{
list.Add(item);
}
return list;
}
// Streams can throw for Length. Eg a http stream that the server has not specified the length header
// Specify buffer to avoid an exception in Stream.CopyToAsync where it reads Length
// https://github.com/dotnet/runtime/issues/43448
public static Task SafeCopy(this Stream source, Stream target)
{
if (source.CanReadLength())
{
return source.CopyToAsync(target);
}
return source.CopyToAsync(target, 81920);
}
public static bool CanSeekAndReadLength(this Stream stream) =>
stream.CanSeek &&
CanReadLength(stream);
static bool CanReadLength(this Stream stream)
{
try
{
var streamLength = stream.Length;
}
catch (NotImplementedException)
{
return false;
}
catch (NotSupportedException)
{
return false;
}
return true;
}
public static string TrimPreamble(this string text) =>
text.TrimStart('\uFEFF');
public static void Enqueue<T>(this Queue<T> queue, IEnumerable<T> items)
{
foreach (var item in items)
{
queue.Enqueue(item);
}
}
public static CharSpan AsSpan(this StringBuilder builder) =>
builder
.ToString()
.AsSpan();
public static List<T> Clone<T>(this List<T> original) =>
[..original];
public static IReadOnlyList<string>? ParameterNames(this MethodInfo method)
{
var parameters = method.GetParameters();
if (parameters.Length == 0)
{
return null;
}
return parameters
.Select(_ => _.Name!)
.ToList();
}
public static Dictionary<TKey, TValue> Clone<TKey, TValue>(this Dictionary<TKey, TValue> original)
where TValue : struct
where TKey : notnull => new(original);
public static Dictionary<TKey, TValue?> Clone<TKey, TValue>(this Dictionary<TKey, TValue?> original)
where TValue : struct
where TKey : notnull => new(original);
#region NameWithParent
public static string NameWithParent(this Type type)
{
if (type.IsNested)
{
return $"{type.ReflectedType!.Name}.{type.Name}";
}
return type.Name;
}
#endregion
public static string? Configuration(this Assembly assembly)
{
var attribute = assembly.GetCustomAttribute<AssemblyConfigurationAttribute>();
return attribute?.Configuration;
}
public static char? FirstChar(this StringBuilder builder)
{
if (builder.Length > 0)
{
return builder[0];
}
return null;
}
public static char? LastChar(this StringBuilder builder)
{
if (builder.Length > 0)
{
return builder[^1];
}
return null;
}
public static void FilterLines(this StringBuilder input, Func<string, bool> removeLine)
{
var theString = input.ToString();
using var reader = new StringReader(theString);
input.Clear();
while (reader.ReadLine() is { } line)
{
if (removeLine(line))
{
continue;
}
input.AppendLineN(line);
}
if (input.Length > 0 &&
!theString.EndsWith('\n'))
{
input.Length -= 1;
}
}
public static void RemoveEmptyLines(this StringBuilder builder)
{
builder.FilterLines(string.IsNullOrWhiteSpace);
if (builder.FirstChar() is '\n')
{
builder.Remove(0, 1);
}
if (builder.LastChar() is '\n')
{
builder.Length--;
}
}
public static string Remove(this string value, string toRemove) =>
value.Replace(toRemove, "");
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> factory)
where TKey : notnull
{
if (dictionary.TryGetValue(key, out var value))
{
return value;
}
return dictionary[key] = factory(key);
}
public static void ReplaceIfLonger(this StringBuilder builder, string oldValue, string newValue)
{
if (builder.Length < oldValue.Length)
{
return;
}
builder.Replace(oldValue, newValue);
}
public static void Overwrite(this StringBuilder builder, string value, int index, int length)
{
builder.Remove(index, length);
builder.Insert(index, value);
}
public static int Count(this StringBuilder builder, char ch)
{
var count = 0;
for (var index = 0; index < builder.Length; index++)
{
if (builder[index] == ch)
{
count++;
}
}
return count;
}
public static bool IsException(this Type type) =>
type.IsAssignableTo<Exception>();
}