├── AssemblyInfo.cs
├── AssemblyInfo.cs.meta
├── Assert.Group.cs
├── Assert.Group.cs.meta
├── Assert.cs
├── Assert.cs.meta
├── C Sharp Dev Tools.asmdef
├── C Sharp Dev Tools.asmdef.meta
├── Dump.cs
├── Dump.cs.meta
├── Extensions.meta
├── Extensions
├── DirectoryExtensions.cs
├── DirectoryExtensions.cs.meta
├── GenericExtensions.cs
└── GenericExtensions.cs.meta
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── Unity.meta
├── Unity
├── Editor.meta
└── Editor
│ ├── DebugBurstIntrinsicsWindow.cs
│ ├── DebugBurstIntrinsicsWindow.cs.meta
│ ├── SafetyCheckSettingsWindow.cs
│ └── SafetyCheckSettingsWindow.cs.meta
├── UnreachableException.cs
├── UnreachableException.cs.meta
├── bitcoin_address.txt
├── donate_bitcoin.png
├── manifest.json
├── manifest.json.meta
├── package.json
└── package.json.meta
/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("C Sharp Dev Tools")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("C Sharp Dev Tools")]
12 | [assembly: AssemblyCopyright("Copyright � 2020 - 2024 Maximilian Kalimon")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("468e6d94-5fed-477d-8823-a81958b82a8a")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | //
32 | [assembly: AssemblyVersion("1.0.10")]
33 | [assembly: AssemblyFileVersion("1.0.10")]
--------------------------------------------------------------------------------
/AssemblyInfo.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7ca8cf387ca802d4ab335bf68f789a7f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assert.Group.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.IO;
5 | using System.Reflection;
6 | using System.Threading.Tasks;
7 |
8 | namespace DevTools
9 | {
10 | public static partial class Assert
11 | {
12 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
13 | internal class GroupAttribute : Attribute
14 | {
15 | internal const string __FILE__BOOLEAN_CONDITION_CHECKS = "BOOLEAN_CONDITION_CHECKS";
16 | internal const string __FILE__NULL_CHECKS = "NULL_CHECKS";
17 | internal const string __FILE__FILE_PATH_CHECKS = "FILE_PATH_CHECKS";
18 | internal const string __FILE__ARRAY_BOUNDS_CHECKS = "ARRAY_BOUNDS_CHECKS";
19 | internal const string __FILE__COMPARISON_CHECKS = "COMPARISON_CHECKS";
20 | internal const string __FILE__ARITHMETIC_LOGIC_CHECKS = "ARITHMETIC_LOGIC_CHECKS";
21 | internal const string __FILE__MEMORY_CHECKS = "MEMORY_CHECKS";
22 |
23 | /// Boolean Condition Checks
24 | internal const string __NAME__BOOLEAN_CONDITION_CHECKS = "Boolean Condition Checks";
25 | /// Null Checks
26 | internal const string __NAME__NULL_CHECKS = "Null Checks";
27 | /// File Path Checks
28 | internal const string __NAME__FILE_PATH_CHECKS = "File Path Checks";
29 | /// Array Bounds Checks
30 | internal const string __NAME__ARRAY_BOUNDS_CHECKS = "Array Bounds Checks";
31 | /// Comparison Checks
32 | internal const string __NAME__COMPARISON_CHECKS = "Comparison Checks";
33 | /// Arithmetic-Logic Checks
34 | internal const string __NAME__ARITHMETIC_LOGIC_CHECKS = "Arithmetic-Logic Checks";
35 | /// Memory Checks
36 | internal const string __NAME__MEMORY_CHECKS = "Memory Checks";
37 |
38 | private GroupAttribute() { }
39 | internal GroupAttribute(string publicName)
40 | {
41 | PublicName = publicName;
42 | FileContent = Defines.Where(grp => grp.PublicName == publicName).First().FileContent;
43 | }
44 |
45 | internal string FileContent { get; private set; }
46 | internal string PublicName { get; private set; }
47 |
48 | internal static Assert.GroupAttribute[] Defines => new Assert.GroupAttribute[]
49 | {
50 | new Assert.GroupAttribute{ FileContent = __FILE__BOOLEAN_CONDITION_CHECKS, PublicName = __NAME__BOOLEAN_CONDITION_CHECKS },
51 | new Assert.GroupAttribute{ FileContent = __FILE__NULL_CHECKS, PublicName = __NAME__NULL_CHECKS },
52 | new Assert.GroupAttribute{ FileContent = __FILE__FILE_PATH_CHECKS, PublicName = __NAME__FILE_PATH_CHECKS },
53 | new Assert.GroupAttribute{ FileContent = __FILE__ARRAY_BOUNDS_CHECKS, PublicName = __NAME__ARRAY_BOUNDS_CHECKS },
54 | new Assert.GroupAttribute{ FileContent = __FILE__COMPARISON_CHECKS, PublicName = __NAME__COMPARISON_CHECKS },
55 | new Assert.GroupAttribute{ FileContent = __FILE__ARITHMETIC_LOGIC_CHECKS, PublicName = __NAME__ARITHMETIC_LOGIC_CHECKS },
56 | new Assert.GroupAttribute{ FileContent = __FILE__MEMORY_CHECKS, PublicName = __NAME__MEMORY_CHECKS }
57 | };
58 | private static string[] KnownUsingsWithAssertClasses => new string[]
59 | {
60 | "using NUnit.Framework;",
61 | "using UnityEngine.Assertions",
62 | "using static System.Diagnostics.Debug;"
63 | };
64 |
65 | internal static async Task> CountMethodCallsAsync(string projectPath)
66 | {
67 | try
68 | {
69 | Dictionary methodToGroupMap = GetAssertionsMappedToGroups();
70 | List>> jobs = CreateCountingTasks(methodToGroupMap, projectPath);
71 |
72 | return await CombineResults(jobs);
73 | }
74 | catch (Exception ex)
75 | {
76 | ex.Log();
77 | return null;
78 | }
79 | }
80 | private static bool ContainsOverload(Dictionary result, MethodInfo method)
81 | {
82 | foreach (KeyValuePair item in result)
83 | {
84 | if (item.Key.Name == method.Name)
85 | {
86 | return true;
87 | }
88 | }
89 |
90 | return false;
91 | }
92 | private static Dictionary GetAssertionsMappedToGroups()
93 | {
94 | Dictionary result = new Dictionary();
95 |
96 | foreach (MethodInfo method in typeof(Assert).GetMethods())
97 | {
98 | Assert.GroupAttribute attribute = method.GetCustomAttribute(false);
99 | if (attribute != null && !ContainsOverload(result, method))
100 | {
101 | result.Add(method, attribute);
102 | }
103 | }
104 |
105 | return result;
106 | }
107 | private static string GetMethodPrefixFromUsingStatements(string script)
108 | {
109 | if (script.Contains("using static DevTools.Assert;"))
110 | {
111 | return string.Empty;
112 | }
113 | else if (script.Contains("using DevTools;") && KnownUsingsWithAssertClasses.All(__using => !script.Contains(__using)))
114 | {
115 | return "Assert.";
116 | }
117 | else
118 | {
119 | return "DevTools.Assert.";
120 | }
121 | }
122 | private static uint CountSubstrings(string instance, string value)
123 | {
124 | Assert.IsFalse(string.IsNullOrEmpty(value));
125 |
126 | uint count = 0;
127 | int index = instance.IndexOf(value);
128 | while (index != -1 & index < instance.Length)
129 | {
130 | count++;
131 | index = instance.IndexOf(value, index + value.Length);
132 | }
133 |
134 | return count;
135 | }
136 | private static List>> CreateCountingTasks(Dictionary methodToGroupMap, string path)
137 | {
138 | List>> tasks = new List>>(256);
139 |
140 | DirectoryExtensions.ForEachFile(path,
141 | (file) =>
142 | {
143 | if (Path.GetExtension(file) != ".cs")
144 | {
145 | return;
146 | }
147 |
148 | tasks.Add(Task>.Factory.StartNew(
149 | () =>
150 | {
151 | Dictionary callCounts = new Dictionary();
152 | string script = File.ReadAllText(file);
153 | string prefix = GetMethodPrefixFromUsingStatements(script);
154 |
155 | foreach (KeyValuePair methodMapping in methodToGroupMap)
156 | {
157 | Assert.GroupAttribute group = methodMapping.Value;
158 | uint numCalls = CountSubstrings(script, prefix + methodMapping.Key.Name);
159 |
160 | if (callCounts.ContainsKey(group))
161 | {
162 | callCounts[group] += numCalls;
163 | }
164 | else
165 | {
166 | callCounts.Add(group, numCalls);
167 | }
168 | }
169 |
170 | return callCounts;
171 | }));
172 | });
173 |
174 | return tasks;
175 | }
176 | private static async Task> CombineResults(List>> jobs)
177 | {
178 | Dictionary result = await jobs[0]; // at the very least this very script is assigned a job
179 |
180 | for (int i = 1; i < jobs.Count; i++)
181 | {
182 | foreach (KeyValuePair callCount in await jobs[i])
183 | {
184 | result[callCount.Key] += callCount.Value;
185 | }
186 | }
187 |
188 | return result;
189 | }
190 | }
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/Assert.Group.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3a77b5ee8b1a45047bb10197e1025b08
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Assert.cs:
--------------------------------------------------------------------------------
1 | // Constraints:
2 | // No use of the ConditionalAttribute
3 | // strings, Exceptions or any other managed objects cannot be passed as arguments to functions if they are to work with Unity.Burst
4 |
5 | #if DEBUG
6 |
7 | #define BOOLEAN_CONDITION_CHECKS
8 | #define NULL_CHECKS
9 | #define FILE_PATH_CHECKS
10 | #define ARRAY_BOUNDS_CHECKS
11 | #define COMPARISON_CHECKS
12 | #define ARITHMETIC_LOGIC_CHECKS
13 | #define MEMORY_CHECKS
14 |
15 | #endif
16 |
17 | using System;
18 | using System.IO;
19 | using System.Runtime.CompilerServices;
20 |
21 | namespace DevTools
22 | {
23 | public static partial class Assert
24 | {
25 | internal const string ASSERTION_FAILED_TAG = "Assertion Failed: ";
26 |
27 |
28 | public static UnreachableException Unreachable()
29 | {
30 | #if DEBUG
31 | throw new UnreachableException();
32 | #else
33 | return null;
34 | #endif
35 | }
36 |
37 | #region BOOLEAN_CONDITION_CHECKS
38 | /// Part of:
39 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
40 | [Assert.Group(Assert.GroupAttribute.__NAME__BOOLEAN_CONDITION_CHECKS)]
41 | public static void IsTrue(bool condition)
42 | {
43 | #if BOOLEAN_CONDITION_CHECKS
44 | if (!condition)
45 | {
46 | throw new Exception(ASSERTION_FAILED_TAG + "Expected 'true'.");
47 | }
48 | #endif
49 | }
50 |
51 | /// Part of:
52 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
53 | [Assert.Group(Assert.GroupAttribute.__NAME__BOOLEAN_CONDITION_CHECKS)]
54 | public static void IsFalse(bool condition)
55 | {
56 | #if BOOLEAN_CONDITION_CHECKS
57 | if (condition)
58 | {
59 | throw new Exception(ASSERTION_FAILED_TAG + "Expected 'false'.");
60 | }
61 | #endif
62 | }
63 | #endregion
64 |
65 | #region NULL_CHECKS
66 | /// Part of:
67 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
68 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
69 | public static void IsNull(object obj)
70 | {
71 | #if NULL_CHECKS
72 | if (obj != null)
73 | {
74 | throw new InvalidDataException(ASSERTION_FAILED_TAG + "Expected null.");
75 | }
76 | #endif
77 | }
78 |
79 | /// Part of:
80 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
81 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
82 | public static void IsNull(T? obj)
83 | where T : struct
84 | {
85 | #if NULL_CHECKS
86 | if (obj != null)
87 | {
88 | throw new InvalidDataException(ASSERTION_FAILED_TAG + "Expected null.");
89 | }
90 | #endif
91 | }
92 |
93 | /// Part of:
94 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
95 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
96 | unsafe public static void IsNull(void* ptr)
97 | {
98 | #if NULL_CHECKS
99 | if (ptr != null)
100 | {
101 | throw new InvalidDataException(ASSERTION_FAILED_TAG + "Expected null.");
102 | }
103 | #endif
104 | }
105 |
106 | /// Part of:
107 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
108 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
109 | public static void IsNotNull(object obj)
110 | {
111 | #if NULL_CHECKS
112 | if (obj == null)
113 | {
114 | throw new NullReferenceException(ASSERTION_FAILED_TAG + "Expected not-null.");
115 | }
116 | #endif
117 | }
118 |
119 | /// Part of:
120 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
121 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
122 | public static void IsNotNull(T? obj)
123 | where T : struct
124 | {
125 | #if NULL_CHECKS
126 | if (obj == null)
127 | {
128 | throw new NullReferenceException(ASSERTION_FAILED_TAG + "Expected not-null.");
129 | }
130 | #endif
131 | }
132 |
133 | /// Part of:
134 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
135 | [Assert.Group(Assert.GroupAttribute.__NAME__NULL_CHECKS)]
136 | unsafe public static void IsNotNull(void* ptr)
137 | {
138 | #if NULL_CHECKS
139 | if (ptr == null)
140 | {
141 | throw new NullReferenceException(ASSERTION_FAILED_TAG + "Expected not-null.");
142 | }
143 | #endif
144 | }
145 | #endregion
146 |
147 | #region FILE_PATH_CHECKS
148 | /// Part of:
149 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
150 | [Assert.Group(Assert.GroupAttribute.__NAME__FILE_PATH_CHECKS)]
151 | public static void FileExists(string path)
152 | {
153 | #if FILE_PATH_CHECKS
154 | IsNotNull(path); // File.Exists only returns 'false' in case 'path' is null (no explicit throw, which is what I want)
155 |
156 | if (!File.Exists(path))
157 | {
158 | throw new FileNotFoundException(ASSERTION_FAILED_TAG + path + " not found");
159 | }
160 | #endif
161 | }
162 | #endregion
163 |
164 | #region ARRAY_BOUNDS_CHECKS
165 | /// Part of:
166 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
167 | [Assert.Group(Assert.GroupAttribute.__NAME__ARRAY_BOUNDS_CHECKS)]
168 | public static void IsWithinArrayBounds(long index, long arrayLength)
169 | {
170 | #if ARRAY_BOUNDS_CHECKS
171 | IsNonNegative(arrayLength);
172 |
173 | if ((ulong)index >= (ulong)arrayLength)
174 | {
175 | throw new IndexOutOfRangeException(ASSERTION_FAILED_TAG + $"{ index } is out of range (length { arrayLength } - 1).");
176 | }
177 | #endif
178 | }
179 |
180 | /// Part of:
181 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
182 | [Assert.Group(Assert.GroupAttribute.__NAME__ARRAY_BOUNDS_CHECKS)]
183 | public static void IsWithinArrayBounds(ulong index, ulong arrayLength)
184 | {
185 | #if ARRAY_BOUNDS_CHECKS
186 | if (index >= arrayLength)
187 | {
188 | throw new IndexOutOfRangeException(ASSERTION_FAILED_TAG + $"{ index } is out of range (length { arrayLength } - 1).");
189 | }
190 | #endif
191 | }
192 |
193 | /// Part of:
194 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
195 | [Assert.Group(Assert.GroupAttribute.__NAME__ARRAY_BOUNDS_CHECKS)]
196 | public static void IsValidSubarray(int index, int numEntries, int arrayLength)
197 | {
198 | #if ARRAY_BOUNDS_CHECKS
199 | IsWithinArrayBounds(index, arrayLength);
200 | IsNonNegative(numEntries);
201 |
202 | if (index + numEntries > arrayLength)
203 | {
204 | throw new IndexOutOfRangeException(ASSERTION_FAILED_TAG + $"{ nameof(index) } + { nameof(numEntries) } is { index + numEntries }, which is larger than length { arrayLength }.");
205 | }
206 | #endif
207 | }
208 |
209 | /// Part of:
210 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
211 | [Assert.Group(Assert.GroupAttribute.__NAME__ARRAY_BOUNDS_CHECKS)]
212 | public static void SubarraysDoNotOverlap(int firstIndex, int secondIndex, int firstNumEntries, int secondNumEntries)
213 | {
214 | #if ARRAY_BOUNDS_CHECKS
215 | if (firstIndex < secondIndex)
216 | {
217 | if (firstIndex + firstNumEntries > secondIndex)
218 | {
219 | throw new IndexOutOfRangeException(ASSERTION_FAILED_TAG + $"Subarray from { firstIndex } to { firstIndex + firstNumEntries - 1} overlaps with subarray from { secondIndex } to { secondIndex + secondNumEntries - 1 }.");
220 | }
221 | }
222 | else
223 | {
224 | if (secondIndex + secondNumEntries > firstIndex)
225 | {
226 | throw new IndexOutOfRangeException(ASSERTION_FAILED_TAG + $"Subarray from { secondIndex } to { secondIndex + secondNumEntries - 1} overlaps with subarray from { firstIndex } to { firstIndex + firstNumEntries - 1 }.");
227 | }
228 | }
229 | #endif
230 | }
231 | #endregion
232 |
233 | #region COMPARISON_CHECKS
234 | /// Part of:
235 | /// Remember: Zero is neither positive nor negative.
236 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
237 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
238 | public static void IsPositive(long value)
239 | {
240 | #if COMPARISON_CHECKS
241 | if (value <= 0)
242 | {
243 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive.");
244 | }
245 | #endif
246 | }
247 |
248 | /// Part of:
249 | /// Remember: Zero is neither positive nor negative.
250 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
251 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
252 | public static void IsPositive(float value)
253 | {
254 | #if COMPARISON_CHECKS
255 | if (value <= 0f)
256 | {
257 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive.");
258 | }
259 | #endif
260 | }
261 |
262 | /// Part of:
263 | /// Remember: Zero is neither positive nor negative.
264 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
265 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
266 | public static void IsPositive(double value)
267 | {
268 | #if COMPARISON_CHECKS
269 | if (value <= 0d)
270 | {
271 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive.");
272 | }
273 | #endif
274 | }
275 |
276 | /// Part of:
277 | /// Remember: Zero is neither positive nor negative.
278 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
279 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
280 | public static void IsPositive(decimal value)
281 | {
282 | #if COMPARISON_CHECKS
283 | if (value <= 0m)
284 | {
285 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive.");
286 | }
287 | #endif
288 | }
289 |
290 | /// Part of:
291 | /// Remember: Zero is neither positive nor negative.
292 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
293 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
294 | public static void IsNegative(long value)
295 | {
296 | #if COMPARISON_CHECKS
297 | if (value >= 0)
298 | {
299 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative.");
300 | }
301 | #endif
302 | }
303 |
304 | /// Part of:
305 | /// Remember: Zero is neither positive nor negative.
306 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
307 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
308 | public static void IsNegative(float value)
309 | {
310 | #if COMPARISON_CHECKS
311 | if (value >= 0f)
312 | {
313 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative.");
314 | }
315 | #endif
316 | }
317 |
318 | /// Part of:
319 | /// Remember: Zero is neither positive nor negative.
320 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
321 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
322 | public static void IsNegative(double value)
323 | {
324 | #if COMPARISON_CHECKS
325 | if (value >= 0d)
326 | {
327 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative.");
328 | }
329 | #endif
330 | }
331 |
332 | /// Part of:
333 | /// Remember: Zero is neither positive nor negative.
334 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
335 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
336 | public static void IsNegative(decimal value)
337 | {
338 | #if COMPARISON_CHECKS
339 | if (value >= 0m)
340 | {
341 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative.");
342 | }
343 | #endif
344 | }
345 |
346 | /// Part of:
347 | /// Remember: Zero is neither positive nor negative.
348 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
349 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
350 | public static void IsNonNegative(long value)
351 | {
352 | #if COMPARISON_CHECKS
353 | if (value < 0)
354 | {
355 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive or equal to zero.");
356 | }
357 | #endif
358 | }
359 |
360 | /// Part of:
361 | /// Remember: Zero is neither positive nor negative.
362 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
363 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
364 | public static void IsNonNegative(float value)
365 | {
366 | #if COMPARISON_CHECKS
367 | if (value < 0f)
368 | {
369 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive or equal to zero.");
370 | }
371 | #endif
372 | }
373 |
374 | /// Part of:
375 | /// Remember: Zero is neither positive nor negative.
376 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
377 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
378 | public static void IsNonNegative(double value)
379 | {
380 | #if COMPARISON_CHECKS
381 | if (value < 0d)
382 | {
383 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive or equal to zero.");
384 | }
385 | #endif
386 | }
387 |
388 | /// Part of:
389 | /// Remember: Zero is neither positive nor negative.
390 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
391 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
392 | public static void IsNonNegative(decimal value)
393 | {
394 | #if COMPARISON_CHECKS
395 | if (value < 0m)
396 | {
397 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be positive or equal to zero.");
398 | }
399 | #endif
400 | }
401 |
402 | /// Part of:
403 | /// Remember: Zero is neither positive nor negative.
404 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
405 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
406 | public static void IsNotPositive(long value)
407 | {
408 | #if COMPARISON_CHECKS
409 | if (value > 0)
410 | {
411 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative or equal to zero.");
412 | }
413 | #endif
414 | }
415 |
416 | /// Part of:
417 | /// Remember: Zero is neither positive nor negative.
418 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
419 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
420 | public static void IsNotPositive(float value)
421 | {
422 | #if COMPARISON_CHECKS
423 | if (value > 0f)
424 | {
425 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative or equal to zero.");
426 | }
427 | #endif
428 | }
429 |
430 | /// Part of:
431 | /// Remember: Zero is neither positive nor negative.
432 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
433 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
434 | public static void IsNotPositive(double value)
435 | {
436 | #if COMPARISON_CHECKS
437 | if (value > 0d)
438 | {
439 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative or equal to zero.");
440 | }
441 | #endif
442 | }
443 |
444 | /// Part of:
445 | /// Remember: Zero is neither positive nor negative.
446 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
447 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
448 | public static void IsNotPositive(decimal value)
449 | {
450 | #if COMPARISON_CHECKS
451 | if (value > 0m)
452 | {
453 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be negative or equal to zero.");
454 | }
455 | #endif
456 | }
457 |
458 | /// Part of:
459 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
460 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
461 | public static void AreEqual(T a, T b)
462 | where T : IEquatable
463 | {
464 | #if COMPARISON_CHECKS
465 | if (!a.Equals(b))
466 | {
467 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ a } was expected to be equal to { b }.");
468 | }
469 | #endif
470 | }
471 |
472 | /// Part of:
473 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
474 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
475 | public static void AreNotEqual(T a, T b)
476 | where T : IEquatable
477 | {
478 | #if COMPARISON_CHECKS
479 | if (a.Equals(b))
480 | {
481 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ a } was expected not to be equal to { b }.");
482 | }
483 | #endif
484 | }
485 |
486 | /// Part of:
487 | /// The comparison is inclusive.
488 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
489 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
490 | public static void IsBetween(T value, T min, T max)
491 | where T : IComparable
492 | {
493 | #if COMPARISON_CHECKS
494 | if ((value.CompareTo(min) < 0) || (value.CompareTo(max) > 0))
495 | {
496 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"Min: { min }, Max: { max }, Value: { value }.");
497 | }
498 | #endif
499 | }
500 |
501 | /// Part of:
502 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
503 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
504 | public static void IsSmallerOrEqual(T value, T limit)
505 | where T : IComparable
506 | {
507 | #if COMPARISON_CHECKS
508 | if (value.CompareTo(limit) > 0)
509 | {
510 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be smaller than or equal to { limit }.");
511 | }
512 | #endif
513 | }
514 |
515 | /// Part of:
516 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
517 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
518 | public static void IsSmaller(T value, T limit)
519 | where T : IComparable
520 | {
521 | #if COMPARISON_CHECKS
522 | if (value.CompareTo(limit) > -1)
523 | {
524 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be smaller than { limit }.");
525 | }
526 | #endif
527 | }
528 |
529 | /// Part of:
530 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
531 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
532 | public static void IsGreaterOrEqual(T value, T limit)
533 | where T : IComparable
534 | {
535 | #if COMPARISON_CHECKS
536 | if (value.CompareTo(limit) < 0)
537 | {
538 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be greater than or equal to { limit }.");
539 | }
540 | #endif
541 | }
542 |
543 | /// Part of:
544 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
545 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
546 | public static void IsGreater(T value, T limit)
547 | where T : IComparable
548 | {
549 | #if COMPARISON_CHECKS
550 | if (value.CompareTo(limit) < 1)
551 | {
552 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected to be greater than { limit }.");
553 | }
554 | #endif
555 | }
556 |
557 | /// Part of:
558 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
559 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
560 | public static void IsNotSmaller(T value, T limit)
561 | where T : IComparable
562 | {
563 | #if COMPARISON_CHECKS
564 | if (value.CompareTo(limit) < 0)
565 | {
566 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected not to be smaller than { limit }.");
567 | }
568 | #endif
569 | }
570 |
571 | /// Part of:
572 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
573 | [Assert.Group(Assert.GroupAttribute.__NAME__COMPARISON_CHECKS)]
574 | public static void IsNotGreater(T value, T limit)
575 | where T : IComparable
576 | {
577 | #if COMPARISON_CHECKS
578 | if (value.CompareTo(limit) > 0)
579 | {
580 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"{ value } was expected not to be greater than { limit }.");
581 | }
582 | #endif
583 | }
584 | #endregion
585 |
586 | #region ARITHMETIC_LOGIC_CHECKS
587 | /// Part of:
588 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
589 | [Assert.Group(Assert.GroupAttribute.__NAME__ARITHMETIC_LOGIC_CHECKS)]
590 | unsafe public static void IsSafeBoolean(bool x)
591 | {
592 | #if ARITHMETIC_LOGIC_CHECKS
593 | if (*(byte*)&x > 1)
594 | {
595 | throw new InvalidDataException(ASSERTION_FAILED_TAG + $"The numerical value of the bool { nameof(x) } is { *(byte*)&x } which can lead to undefined behavior.");
596 | }
597 | #endif
598 | }
599 |
600 | /// Part of:
601 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
602 | [Assert.Group(Assert.GroupAttribute.__NAME__ARITHMETIC_LOGIC_CHECKS)]
603 | unsafe public static void IsDefinedBitShift(int amount)
604 | where T : unmanaged
605 | {
606 | #if ARITHMETIC_LOGIC_CHECKS
607 | if ((uint)amount >= (uint)sizeof(T) * 8u)
608 | {
609 | throw new ArgumentOutOfRangeException(ASSERTION_FAILED_TAG + $"Shifting a { typeof(T) } by { amount } results in undefined behavior.");
610 | }
611 | #endif
612 | }
613 |
614 | /// Part of:
615 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
616 | [Assert.Group(Assert.GroupAttribute.__NAME__ARITHMETIC_LOGIC_CHECKS)]
617 | public static void IsDefinedBitShift(uint amount)
618 | where T : unmanaged
619 | {
620 | IsDefinedBitShift((int)amount);
621 | }
622 | #endregion
623 |
624 | #region MEMORY_CHECKS
625 | /// Part of:
626 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
627 | [Assert.Group(Assert.GroupAttribute.__NAME__MEMORY_CHECKS)]
628 | unsafe public static void AreNotAliased(void* ptrA, long bytesA, void* ptrB, long bytesB)
629 | {
630 | #if MEMORY_CHECKS
631 | bool overlap = (ulong)ptrA < (ulong)ptrB && ((ulong)ptrA + (ulong)bytesA - 1 >= (ulong)ptrB);
632 | overlap |= (ulong)ptrB < (ulong)ptrA && ((ulong)ptrB + (ulong)bytesB - 1 >= (ulong)ptrA);
633 | overlap |= (ulong)ptrB == (ulong)ptrA;
634 |
635 | if (overlap)
636 | {
637 | throw new MemberAccessException(ASSERTION_FAILED_TAG + $"The memory block, associated with the base address { Dump.Hex((ulong)ptrA) } and byte length { bytesA } overlaps with the region in memory associated with the base address {Dump.Hex((ulong)ptrB) } and byte length {bytesB }.");
638 | }
639 | #endif
640 | }
641 |
642 | /// Part of:
643 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
644 | [Assert.Group(Assert.GroupAttribute.__NAME__MEMORY_CHECKS)]
645 | unsafe public static void AreNotAliased(T* ptrA, long lengthA, U* ptrB, long lengthB)
646 | where T : unmanaged
647 | where U : unmanaged
648 | {
649 | AreNotAliased((void*)ptrA, sizeof(T) * lengthA, (void*)ptrB, sizeof(U) * lengthB);
650 | }
651 |
652 | /// Part of:
653 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
654 | [Assert.Group(Assert.GroupAttribute.__NAME__MEMORY_CHECKS)]
655 | unsafe public static void IsMemoryAligned(T* ptr)
656 | where T : unmanaged
657 | {
658 | #if MEMORY_CHECKS
659 | switch (sizeof(T))
660 | {
661 | case 2:
662 | case 4:
663 | case 8:
664 | case 16:
665 | case 32:
666 | case 64:
667 | {
668 | if ((ulong)ptr % (uint)sizeof(T) != 0)
669 | {
670 | throw new DataMisalignedException(ASSERTION_FAILED_TAG + $"The address { Dump.Hex((ulong)ptr) } of a { typeof(T) } of size { sizeof(T) } is misaligned by { (ulong)ptr % (uint)sizeof(T) } bytes.");
671 | }
672 |
673 | return;
674 | }
675 |
676 | default: return;
677 | }
678 | #endif
679 | }
680 | #endregion
681 | }
682 | }
--------------------------------------------------------------------------------
/Assert.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 20bf4c6f8edfb304abfb9b8410501193
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/C Sharp Dev Tools.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CSharpDevTools",
3 | "rootNamespace": "DevTools",
4 | "references": [],
5 | "includePlatforms": [],
6 | "excludePlatforms": [],
7 | "allowUnsafeCode": true,
8 | "overrideReferences": false,
9 | "precompiledReferences": [],
10 | "autoReferenced": true,
11 | "defineConstraints": [],
12 | "versionDefines": [],
13 | "noEngineReferences": false
14 | }
--------------------------------------------------------------------------------
/C Sharp Dev Tools.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d744d92b86b337c4fb86945aee2f8304
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Dump.cs:
--------------------------------------------------------------------------------
1 | namespace DevTools
2 | {
3 | unsafe public static class Dump
4 | {
5 | public static string Bits(byte value, bool spaces = true)
6 | {
7 | char* result = stackalloc char[8];
8 |
9 | for (int i = 0; i < 8; i++)
10 | {
11 | result[i] = (char)(((value >> (7 - i)) & 1) + '0');
12 | }
13 |
14 | return new string(result, 0, 8).Insert(4, spaces ? " " : "");
15 | }
16 |
17 | public static string Bits(T value, bool spaces = true)
18 | where T : unmanaged
19 | {
20 | return Bits(&value, sizeof(T), spaces);
21 | }
22 |
23 | public static string Bits(void* ptr, int bytes, bool spaces = true)
24 | {
25 | Assert.IsNotNull(ptr);
26 | Assert.IsNonNegative(bytes);
27 |
28 | byte* address = (byte*)ptr;
29 | string result = string.Empty;
30 |
31 | while (bytes != 0)
32 | {
33 | result = result.Insert(0, Bits(*address, spaces) + (spaces ? " " : ""));
34 |
35 | address++;
36 | bytes--;
37 | }
38 |
39 | return result;
40 | }
41 |
42 |
43 | private static string Hex(byte value, char* HEX_VALUES)
44 | {
45 | char* result = stackalloc char[] { HEX_VALUES[value >> 4], HEX_VALUES[value & 0b1111] };
46 |
47 | return new string(result, 0, 2);
48 | }
49 |
50 | public static string Hex(byte value)
51 | {
52 | char* HEX_VALUES = stackalloc char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
53 |
54 | return Hex(value, HEX_VALUES);
55 | }
56 |
57 | public static string Hex(T value, bool spaces = true)
58 | where T : unmanaged
59 | {
60 | return Hex(&value, sizeof(T), spaces);
61 | }
62 |
63 | public static string Hex(void* ptr, int bytes, bool spaces = true)
64 | {
65 | Assert.IsNotNull(ptr);
66 | Assert.IsNonNegative(bytes);
67 |
68 | char* HEX_VALUES = stackalloc char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
69 |
70 | byte* address = (byte*)ptr;
71 | uint iterations = 0;
72 | string result = string.Empty;
73 |
74 | while (iterations != bytes)
75 | {
76 | string block = Hex(*address, HEX_VALUES);
77 | if (spaces && (iterations != 0) & (iterations % 2 == 0))
78 | {
79 | block += " ";
80 | }
81 | result = result.Insert(0, block);
82 |
83 | address++;
84 | iterations++;
85 | }
86 |
87 | return result;
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Dump.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bc2729170a91dc1439e540270df98def
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 312501a5deed98b49992524a50fa06b6
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Extensions/DirectoryExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Collections.Generic;
4 |
5 | namespace DevTools
6 | {
7 | public static class DirectoryExtensions
8 | {
9 | /// Appends to '' and returns the result.
10 | public static string AsDirectory(this string directory)
11 | {
12 | return directory + Path.DirectorySeparatorChar;
13 | }
14 |
15 | /// Recursively searches for a file '' in the '' directory in a depth-first manner, including subdirectories.
16 | public static string FindInFolder(string folder, string fileName)
17 | {
18 | string result = folder.AsDirectory() + fileName;
19 | if (File.Exists(result))
20 | {
21 | return result;
22 | }
23 |
24 | foreach (string subDirectory in Directory.GetDirectories(folder))
25 | {
26 | result = FindInFolder(subDirectory, fileName);
27 | if (result != null)
28 | {
29 | return result;
30 | }
31 | }
32 |
33 | return null;
34 | }
35 |
36 | /// Deletes a directory '' and all of its contents, including subdirectories.
37 | public static void DeleteFolder(string folder)
38 | {
39 | ForEachDirectory(folder,
40 | (__folder) =>
41 | {
42 | foreach (string file in Directory.GetFiles(__folder))
43 | {
44 | File.Delete(file);
45 | }
46 |
47 | Directory.Delete(__folder);
48 | });
49 | }
50 |
51 | /// Recursively performs an '' on each subdirectory within the directory '' in a depth-first manner.
52 | public static void ForEachDirectory(string folder, Action action)
53 | {
54 | foreach (string subFolder in Directory.GetDirectories(folder))
55 | {
56 | ForEachDirectory(subFolder, action);
57 | action(subFolder);
58 | }
59 | }
60 |
61 | /// Recursively performs an '' on each file within the directory '' in a depth-first manner.
62 | public static void ForEachFile(string folder, Action action)
63 | {
64 | ForEachDirectory(folder,
65 | (__folder) =>
66 | {
67 | foreach (string file in Directory.GetFiles(__folder))
68 | {
69 | action(file);
70 | }
71 | });
72 |
73 | foreach (string file in Directory.GetFiles(folder))
74 | {
75 | action(file);
76 | }
77 | }
78 |
79 | /// Recursively performs a '' on each subdirectory within the directory '' in a depth-first manner.
80 | public static IEnumerable ForEachDirectory(string folder, Func func)
81 | {
82 | foreach (string subFolder in Directory.GetDirectories(folder))
83 | {
84 | ForEachDirectory(subFolder, func);
85 |
86 | yield return func(subFolder);
87 | }
88 | }
89 |
90 | /// Recursively performs a '' on each file within the directory '' in a depth-first manner.
91 | public static IEnumerable ForEachFile(string folder, Func func)
92 | {
93 | List result = new List();
94 |
95 | ForEachFile(folder, (file) => result.Add(func(file)));
96 |
97 | return result;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Extensions/DirectoryExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 22d185dd2222ac4419f2d4f46a6bbf22
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Extensions/GenericExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DevTools
4 | {
5 | public static class GenericExtensions
6 | {
7 | /// Logs a message of type '' to the console.
8 | public static void Log(this T obj)
9 | {
10 | #if DEBUG
11 | #if UNITY_EDITOR
12 | UnityEngine.Debug.Log(obj);
13 | #else
14 | Console.WriteLine(obj);
15 | #endif
16 | #endif
17 | }
18 |
19 | /// Logs a message of type '' to the console.
20 | public static void Log(this T obj, string format, IFormatProvider formatProvider = null)
21 | where T : IFormattable
22 | {
23 | Log(obj.ToString(format, formatProvider));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Extensions/GenericExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 627db4ad663939b44bc9764a5ddfa850
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 - 2021 Maximilian Kalimon
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.
22 |
--------------------------------------------------------------------------------
/LICENSE.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 84de4b1eb35a9b0489b877cae265200d
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C Sharp Dev Tools
2 | C Sharp Dev Tools is a small framework for defensive development with conditionally compiled assertions and logging tools.
3 |
4 | # Donations
5 |
6 | If this repository has been valuable to your projects and you'd like to support my work, consider making a donation.
7 |
8 | [](https://raw.githubusercontent.com/MrUnbelievable92/C-Sharp-Dev-Tools/master/bitcoin_address.txt)
9 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e1aa251fba56aef4f967598b3edb5855
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 75de924e57c81054baa702e76864509c
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Unity/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5d994ecffb5889c47a0c6b52d3e97f44
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Unity/Editor/DebugBurstIntrinsicsWindow.cs:
--------------------------------------------------------------------------------
1 | #if UNITY_EDITOR
2 | using System.IO;
3 | using UnityEngine;
4 | using UnityEditor;
5 |
6 | namespace DevTools.Unity.Editor
7 | {
8 | internal class DebugBurstIntrinsicsWindow : EditorWindow
9 | {
10 | private static string ProjectPath => Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".AsDirectory().Length).AsDirectory() + "LocalPackages";
11 |
12 | private const string SSE = "Sse.IsSseSupported";
13 | private const string SSE2 = "Sse2.IsSse2Supported";
14 | private const string SSE3 = "Sse3.IsSse3Supported";
15 | private const string SSSE3 = "Ssse3.IsSsse3Supported";
16 | private const string SSE4_1 = "Sse4_1.IsSse41Supported";
17 | private const string SSE4_2 = "Sse4_2.IsSse42Supported";
18 | private const string AVX = "Avx.IsAvxSupported";
19 | private const string AVX2 = "Avx2.IsAvx2Supported";
20 | private const string FMA = "Fma.IsFmaSupported";
21 | private const string BMI1 = "Bmi1.IsBmi1Supported";
22 | private const string BMI2 = "Bmi2.IsBmi2Supported";
23 | private const string POPCNT = "Popcnt.IsPopcntSupported";
24 | private const string F16C = "F16C.IsF16CSupported";
25 |
26 | private const string CONST = "Constant.IsConstantExpression";
27 |
28 | private const string TESTING = "#define TESTING";
29 |
30 |
31 | private static bool SkipFile(string file)
32 | {
33 | return Path.GetExtension(file) != ".cs" || Path.GetFileNameWithoutExtension(file) == "DebugBurstIntrinsicsWindow";
34 | }
35 |
36 | private static void DeactivateAll()
37 | {
38 | DeactivateFeatureSet(SSE);
39 | DeactivateFeatureSet(SSE2);
40 | DeactivateFeatureSet(SSE3);
41 | DeactivateFeatureSet(SSSE3);
42 | DeactivateFeatureSet(SSE4_1);
43 | DeactivateFeatureSet(SSE4_2);
44 | DeactivateFeatureSet(AVX);
45 | DeactivateFeatureSet(AVX2);
46 | DeactivateFeatureSet(FMA);
47 | DeactivateFeatureSet(BMI1);
48 | DeactivateFeatureSet(BMI2);
49 | DeactivateFeatureSet(POPCNT);
50 | DeactivateFeatureSet(F16C);
51 | }
52 |
53 | private static void DeactivatePreprocessorDirective(string define)
54 | {
55 | DirectoryExtensions.ForEachFile(ProjectPath,
56 | (file) =>
57 | {
58 | if (SkipFile(file))
59 | {
60 | return;
61 | }
62 |
63 | string fileContent = File.ReadAllText(file);
64 |
65 | if (!fileContent.Contains("//" + define))
66 | {
67 | fileContent = fileContent.Replace(define, "//" + define);
68 | File.WriteAllText(file, fileContent);
69 | }
70 | });
71 | }
72 |
73 | private static void ActivatePreprocessorDirective(string define)
74 | {
75 | DirectoryExtensions.ForEachFile(ProjectPath,
76 | (file) =>
77 | {
78 | if (SkipFile(file))
79 | {
80 | return;
81 | }
82 |
83 | string fileContent = File.ReadAllText(file);
84 |
85 | if (fileContent.Contains("//" + define))
86 | {
87 | fileContent = fileContent.Replace("//" + define, define);
88 | File.WriteAllText(file, fileContent);
89 | }
90 | });
91 | }
92 |
93 | private static void DeactivateFeatureSet(string featureSet)
94 | {
95 | DirectoryExtensions.ForEachFile(ProjectPath,
96 | (file) =>
97 | {
98 | if (SkipFile(file))
99 | {
100 | return;
101 | }
102 |
103 | string fileContent = File.ReadAllText(file);
104 |
105 | bool any = false;
106 | int index = 0;
107 | while ((index = fileContent.IndexOf("!" + featureSet, index + 1)) != -1)
108 | {
109 | any = true;
110 | fileContent = fileContent.Remove(index, 1);
111 | }
112 |
113 | if (any)
114 | {
115 | File.WriteAllText(file, fileContent);
116 | }
117 | });
118 | }
119 |
120 | private static void ActivateFeatureSet(string featureSet)
121 | {
122 | DirectoryExtensions.ForEachFile(ProjectPath,
123 | (file) =>
124 | {
125 | if (SkipFile(file))
126 | {
127 | return;
128 | }
129 |
130 | string fileContent = File.ReadAllText(file);
131 |
132 | bool any = false;
133 | int index = 0;
134 | while ((index = fileContent.IndexOf(featureSet, index + 1)) != -1)
135 | {
136 | any = true;
137 | if (fileContent[index - 1] != '!')
138 | {
139 | fileContent = fileContent.Insert(index, "!");
140 | index++;
141 | }
142 | }
143 |
144 | if (any)
145 | {
146 | File.WriteAllText(file, fileContent);
147 | }
148 | });
149 | }
150 |
151 |
152 | public static void ACTIVATE_TEST_MODE()
153 | {
154 | ActivatePreprocessorDirective(TESTING);
155 |
156 | AssetDatabase.Refresh();
157 | }
158 |
159 | public static void ACTIVATE_SSE()
160 | {
161 | DeactivateAll();
162 |
163 | ActivateFeatureSet(SSE);
164 |
165 | AssetDatabase.Refresh();
166 | }
167 |
168 | public static void ACTIVATE_SSE2()
169 | {
170 | DeactivateAll();
171 |
172 | ActivateFeatureSet(SSE);
173 | ActivateFeatureSet(SSE2);
174 |
175 | AssetDatabase.Refresh();
176 | }
177 |
178 | public static void ACTIVATE_SSE3()
179 | {
180 | DeactivateAll();
181 |
182 | ActivateFeatureSet(SSE);
183 | ActivateFeatureSet(SSE2);
184 | ActivateFeatureSet(SSE3);
185 |
186 | AssetDatabase.Refresh();
187 | }
188 |
189 | public static void ACTIVATE_SSSE3()
190 | {
191 | DeactivateAll();
192 |
193 | ActivateFeatureSet(SSE);
194 | ActivateFeatureSet(SSE2);
195 | ActivateFeatureSet(SSE3);
196 | ActivateFeatureSet(SSSE3);
197 |
198 | AssetDatabase.Refresh();
199 | }
200 |
201 | public static void ACTIVATE_SSE4_1()
202 | {
203 | DeactivateAll();
204 |
205 | ActivateFeatureSet(SSE);
206 | ActivateFeatureSet(SSE2);
207 | ActivateFeatureSet(SSE3);
208 | ActivateFeatureSet(SSSE3);
209 | ActivateFeatureSet(SSE4_1);
210 |
211 | AssetDatabase.Refresh();
212 | }
213 |
214 | public static void ACTIVATE_SSE4_2()
215 | {
216 | DeactivateAll();
217 |
218 | ActivateFeatureSet(SSE);
219 | ActivateFeatureSet(SSE2);
220 | ActivateFeatureSet(SSE3);
221 | ActivateFeatureSet(SSSE3);
222 | ActivateFeatureSet(SSE4_1);
223 | ActivateFeatureSet(SSE4_2);
224 |
225 | AssetDatabase.Refresh();
226 | }
227 |
228 | public static void ACTIVATE_AVX()
229 | {
230 | DeactivateAll();
231 |
232 | ActivateFeatureSet(SSE);
233 | ActivateFeatureSet(SSE2);
234 | ActivateFeatureSet(SSE3);
235 | ActivateFeatureSet(SSSE3);
236 | ActivateFeatureSet(SSE4_1);
237 | ActivateFeatureSet(SSE4_2);
238 | ActivateFeatureSet(AVX);
239 |
240 | AssetDatabase.Refresh();
241 | }
242 |
243 | public static void ACTIVATE_AVX2()
244 | {
245 | DeactivateAll();
246 |
247 | ActivateFeatureSet(SSE);
248 | ActivateFeatureSet(SSE2);
249 | ActivateFeatureSet(SSE3);
250 | ActivateFeatureSet(SSSE3);
251 | ActivateFeatureSet(SSE4_1);
252 | ActivateFeatureSet(SSE4_2);
253 | ActivateFeatureSet(AVX);
254 | ActivateFeatureSet(AVX2);
255 | ActivateFeatureSet(FMA);
256 | ActivateFeatureSet(BMI1);
257 | ActivateFeatureSet(BMI2);
258 | ActivateFeatureSet(POPCNT);
259 | ActivateFeatureSet(F16C);
260 |
261 | AssetDatabase.Refresh();
262 | }
263 |
264 | public static void ACTIVATE_CONST()
265 | {
266 | DeactivateFeatureSet(CONST);
267 |
268 | ActivateFeatureSet(CONST);
269 |
270 | AssetDatabase.Refresh();
271 | }
272 |
273 | public static void RELEASE_MODE()
274 | {
275 | DeactivatePreprocessorDirective(TESTING);
276 |
277 | DeactivateAll();
278 |
279 | DeactivateFeatureSet(CONST);
280 |
281 | AssetDatabase.Refresh();
282 | }
283 |
284 | private static void DrawLine()
285 | {
286 | Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(1));
287 | r.height = 1;
288 | r.x -= 2 ;
289 | r.width += 6;
290 | EditorGUI.DrawRect(r, Color.black);
291 | }
292 |
293 |
294 | [MenuItem("Window/C# Dev Tools/Debug Burst Intrinsics (Local Packages Only)")]
295 | private static void ShowWindow()
296 | {
297 | GetWindow("Debug Burst Intrinsics");
298 | }
299 |
300 | private void OnGUI()
301 | {
302 | GUILayout.Label("Set Code Path:");
303 |
304 | if (GUILayout.Button("SSE", GUILayout.ExpandWidth(false)))
305 | {
306 | ACTIVATE_SSE();
307 | }
308 | if (GUILayout.Button("SSE2", GUILayout.ExpandWidth(false)))
309 | {
310 | ACTIVATE_SSE2();
311 | }
312 | if (GUILayout.Button("SSE3", GUILayout.ExpandWidth(false)))
313 | {
314 | ACTIVATE_SSE3();
315 | }
316 | if (GUILayout.Button("SSSE3", GUILayout.ExpandWidth(false)))
317 | {
318 | ACTIVATE_SSSE3();
319 | }
320 | if (GUILayout.Button("SSE4.1", GUILayout.ExpandWidth(false)))
321 | {
322 | ACTIVATE_SSE4_1();
323 | }
324 | if (GUILayout.Button("SSE4.2", GUILayout.ExpandWidth(false)))
325 | {
326 | ACTIVATE_SSE4_2();
327 | }
328 | if (GUILayout.Button("AVX", GUILayout.ExpandWidth(false)))
329 | {
330 | ACTIVATE_AVX();
331 | }
332 | if (GUILayout.Button("AVX2", GUILayout.ExpandWidth(false)))
333 | {
334 | ACTIVATE_AVX2();
335 | }
336 |
337 | GUILayout.Space(10);
338 |
339 | if (GUILayout.Button("IsConstantExpression", GUILayout.ExpandWidth(false)))
340 | {
341 | ACTIVATE_CONST();
342 | }
343 |
344 | GUILayout.Space(10);
345 |
346 | if (GUILayout.Button("Activate 'TESTING' Preprocessor Directive", GUILayout.ExpandWidth(false)))
347 | {
348 | ACTIVATE_TEST_MODE();
349 | }
350 |
351 | GUILayout.Space(5);
352 |
353 | DrawLine();
354 |
355 | GUILayout.Space(5);
356 |
357 | if (GUILayout.Button("Reset to Release Mode", GUILayout.ExpandWidth(false)))
358 | {
359 | RELEASE_MODE();
360 | }
361 | }
362 | }
363 | }
364 | #endif
--------------------------------------------------------------------------------
/Unity/Editor/DebugBurstIntrinsicsWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 221517bbab969584faff302f516e5894
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Unity/Editor/SafetyCheckSettingsWindow.cs:
--------------------------------------------------------------------------------
1 | #if UNITY_EDITOR
2 | using System;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 | using UnityEditor;
8 | using UnityEngine;
9 |
10 | namespace DevTools.Unity.Editor
11 | {
12 | internal class SafetyCheckSettingsWindow : EditorWindow
13 | {
14 | private const string FOLDER_NAME = "C Sharp Dev Tools";
15 | private const string FILE_NAME = "Assert.cs";
16 | private const string ALL_CHECKS = "All Checks";
17 | private const string LOADING = "???";
18 | private const string APPLY = "Apply";
19 |
20 | private bool firstLoad;
21 | private bool anythingChanged;
22 |
23 | private Dictionary methodCallCounts = null;
24 | private Dictionary definesToCheckMarks;
25 |
26 |
27 | private static string ProjectPath => Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".AsDirectory().Length);
28 | private static string ScriptPath
29 | {
30 | get
31 | {
32 | string defaultPath = ProjectPath.AsDirectory() + "LocalPackages".AsDirectory() + FOLDER_NAME.AsDirectory() + FILE_NAME;
33 |
34 | if (File.Exists(defaultPath))
35 | {
36 | return defaultPath;
37 | }
38 | else
39 | {
40 | return DirectoryExtensions.FindInFolder(ProjectPath, FILE_NAME) ?? throw new DllNotFoundException($"'{ FOLDER_NAME.AsDirectory() + FILE_NAME }' was modified and cannot be found. Enabling/Disabling assertions in the editor is not supported.");
41 | }
42 | }
43 | }
44 |
45 | private ulong TotalMethodCalls
46 | {
47 | get
48 | {
49 | ulong count = 0;
50 |
51 | foreach (KeyValuePair assertion in methodCallCounts)
52 | {
53 | count += assertion.Value;
54 | }
55 |
56 | return count;
57 | }
58 | }
59 |
60 | private bool AllChecks
61 | {
62 | get
63 | {
64 | bool result = true;
65 |
66 | foreach (KeyValuePair checkMark in definesToCheckMarks.ToList())
67 | {
68 | result &= definesToCheckMarks[checkMark.Key];
69 | }
70 |
71 | return result;
72 | }
73 |
74 | set
75 | {
76 | foreach (KeyValuePair checkMark in definesToCheckMarks.ToList())
77 | {
78 | definesToCheckMarks[checkMark.Key] = value;
79 | }
80 | }
81 | }
82 |
83 |
84 | private string UpdateCondition(string fileContent, Assert.GroupAttribute assertionGroup)
85 | {
86 | bool conditionValueInEditor = definesToCheckMarks[assertionGroup];
87 |
88 | if (conditionValueInEditor && !IsEnabled(fileContent, assertionGroup))
89 | {
90 | fileContent = Enable(fileContent, assertionGroup);
91 | }
92 | else if (!conditionValueInEditor && IsEnabled(fileContent, assertionGroup))
93 | {
94 | fileContent = Disable(fileContent, assertionGroup);
95 | }
96 |
97 | return fileContent;
98 | }
99 |
100 | private void WriteToFile()
101 | {
102 | StreamReader reader = new StreamReader(ScriptPath);
103 | string fileContent = reader.ReadToEnd();
104 |
105 | foreach (KeyValuePair map in definesToCheckMarks)
106 | {
107 | fileContent = UpdateCondition(fileContent, map.Key);
108 | }
109 |
110 | anythingChanged = false;
111 |
112 | reader.Dispose();
113 | File.WriteAllText(ScriptPath, fileContent);
114 | AssetDatabase.Refresh();
115 | }
116 |
117 | private bool IsEnabled(string fileContent, Assert.GroupAttribute assertionGroup)
118 | {
119 | return fileContent.Substring(fileContent.IndexOf("#define " + assertionGroup.FileContent) - 2, 2) != "//";
120 | }
121 |
122 | private string Enable(string fileContent, Assert.GroupAttribute assertionGroup)
123 | {
124 | Assert.IsFalse(IsEnabled(fileContent, assertionGroup));
125 |
126 | return fileContent.Remove(fileContent.IndexOf("#define " + assertionGroup.FileContent) - 2, 2);
127 | }
128 |
129 | private string Disable(string fileContent, Assert.GroupAttribute assertionGroup)
130 | {
131 | Assert.IsTrue(IsEnabled(fileContent, assertionGroup));
132 |
133 | return fileContent.Insert(fileContent.IndexOf("#define " + assertionGroup.FileContent), "//");
134 | }
135 |
136 | private string GetAssertionGroupCallCountSuffix(Assert.GroupAttribute key = null)
137 | {
138 | bool loading = methodCallCounts == null;
139 | ulong calls = key == null ? (loading ? 0 : TotalMethodCalls) : (loading ? 0 : methodCallCounts[key]);
140 |
141 | return " (" +
142 | (loading ? LOADING : calls.ToString()) +
143 | " call" + (calls == 1 ? string.Empty : "s") +
144 | ")";
145 | }
146 |
147 |
148 | [MenuItem("Window/C# Dev Tools/Manage Safety Checks...")]
149 | private static void ShowWindow()
150 | {
151 | GetWindow("C# Dev Tools Safety Checks");
152 | }
153 |
154 | private void OnEnable()
155 | {
156 | string projectPath = ProjectPath; // <- Only allowed on the main thread in Unity
157 | string scriptPath = ScriptPath; // <- Only allowed on the main thread in Unity
158 |
159 | Task.Run(() =>
160 | {
161 | try
162 | {
163 | StreamReader reader = new StreamReader(scriptPath);
164 | string fileContent = reader.ReadToEnd();
165 | reader.Dispose();
166 |
167 | Assert.GroupAttribute[] defines = Assert.GroupAttribute.Defines;
168 | definesToCheckMarks = new Dictionary(defines.Length);
169 | for (int i = 0; i < defines.Length; i++)
170 | {
171 | definesToCheckMarks.Add(defines[i], IsEnabled(fileContent, defines[i]));
172 | }
173 |
174 | firstLoad = true;
175 |
176 | Task.Run(async () => methodCallCounts = await Assert.GroupAttribute.CountMethodCallsAsync(projectPath));
177 | }
178 | catch (Exception ex)
179 | {
180 | ex.Log();
181 | firstLoad = false;
182 | }
183 | });
184 | }
185 |
186 | unsafe private void OnGUI()
187 | {
188 | if (!firstLoad) return;
189 |
190 |
191 | bool _allChecks = GUILayout.Toggle(AllChecks, " " + ALL_CHECKS + GetAssertionGroupCallCountSuffix(null));
192 |
193 | GUILayout.Space(10);
194 |
195 | const byte OFFSET_BETWEEN_CHECKBOXES = 2;
196 | bool* conditions = stackalloc bool[definesToCheckMarks.Count];
197 | int iterations = 0;
198 | foreach (KeyValuePair item in definesToCheckMarks.ToList())
199 | {
200 | conditions[iterations++] = GUILayout.Toggle(item.Value, " " + item.Key.PublicName + GetAssertionGroupCallCountSuffix(item.Key));
201 | GUILayout.Space(OFFSET_BETWEEN_CHECKBOXES);
202 | }
203 |
204 | GUILayout.Space(15 - OFFSET_BETWEEN_CHECKBOXES);
205 |
206 | bool _anythingChanged = _allChecks != AllChecks;
207 |
208 | if (_anythingChanged)
209 | {
210 | AllChecks = _allChecks;
211 | }
212 | else
213 | {
214 | iterations = 0;
215 |
216 | foreach (KeyValuePair item in definesToCheckMarks.ToList())
217 | {
218 | _anythingChanged |= (conditions[iterations] != item.Value);
219 | definesToCheckMarks[item.Key] = (conditions[iterations] != item.Value) ? conditions[iterations] : item.Value;
220 | iterations++;
221 | }
222 | }
223 |
224 | bool pressedApplyButton = GUILayout.Button(APPLY, GUILayout.ExpandWidth(false));
225 | anythingChanged |= _anythingChanged;
226 | if (anythingChanged & pressedApplyButton)
227 | {
228 | WriteToFile();
229 | }
230 |
231 | GUILayout.Space(10);
232 | }
233 | }
234 | }
235 | #endif
--------------------------------------------------------------------------------
/Unity/Editor/SafetyCheckSettingsWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 79f06f739a8bd41469cb16b61a6d152a
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/UnreachableException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DevTools
4 | {
5 | public class UnreachableException : Exception
6 | {
7 | public UnreachableException()
8 | : base($"{ Assert.ASSERTION_FAILED_TAG } Attempted to execute unreachable code.")
9 | {
10 |
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/UnreachableException.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 20b51057f15ede64596b3a77fc2a4367
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/bitcoin_address.txt:
--------------------------------------------------------------------------------
1 | bc1qdyyfwh8k8f7l6ces9vw9y0wtzn7lpq9gt0g3md
--------------------------------------------------------------------------------
/donate_bitcoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MrUnbelievable92/C-Sharp-Dev-Tools/99363a64b86857af0e2fdaf8873c2e393e51d3a8/donate_bitcoin.png
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "csharpdevtools",
3 | "displayName": "C Sharp Dev Tools",
4 | "version": "1.0.10",
5 | "description": "C Sharp Dev Tools is a small framework for defensive development with conditionally compiled assertions and logging tools.",
6 | "author": {
7 | "name": "Maximilian Kalimon",
8 | "email": "mkalimon@gmx.de"
9 | },
10 | "repository": {
11 | "url": "https://github.com/MrUnbelievable92/C-Sharp-Dev-Tools",
12 | "type": "git"
13 | },
14 | "type": "library"
15 | }
--------------------------------------------------------------------------------
/manifest.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 808366cba4ceaff49843e6578eee3337
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "csharpdevtools",
3 | "displayName": "C Sharp Dev Tools",
4 | "version": "1.0.10",
5 | "description": "C Sharp Dev Tools is a small framework for defensive development with conditionally compiled assertions and logging tools.",
6 | "author": {
7 | "name": "Maximilian Kalimon",
8 | "email": "mkalimon@gmx.de"
9 | },
10 | "repository": {
11 | "url": "https://github.com/MrUnbelievable92/C-Sharp-Dev-Tools",
12 | "type": "git"
13 | },
14 | "type": "library"
15 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5400a7ed7d5791f4f888af7d77890c5a
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------