Compare commits

...

303 Commits

Author SHA1 Message Date
Chris Cameron
11004085c5 chore: Updating changelog, incrementing minor version 2019-09-16 14:44:07 -04:00
Chris Cameron
6ca015a561 Merge branch 'feat/ProgramDataPath' of Common/Utils into dev 2019-09-16 18:19:58 +00:00
Drew Tingen
73b1c4819c chore: Update changelog 2019-09-16 14:10:45 -04:00
Drew Tingen
f913af6efe Merge remote-tracking branch 'origin/dev' into feat/ProgramDataPath 2019-09-16 14:05:48 -04:00
Drew Tingen
099517df7d feat: Adding program data path to PathUtils 2019-09-16 14:00:47 -04:00
Chris Cameron
6a7b58f50f docs: Updating changelog 2019-09-14 11:23:19 -04:00
Chris Cameron
2273d5b3a1 refactor: Removing unused code 2019-09-14 11:23:09 -04:00
Chris Cameron
aa17f29305 feat: Adding BinarySearch extension method for ILists 2019-09-13 16:35:38 -04:00
Chris Cameron
e65578584a docs: Updating changelog 2019-09-10 17:19:28 -04:00
Chris Cameron
96d2df8871 feat: Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting 2019-09-10 17:19:00 -04:00
Chris Cameron
b4d82a855e feat: Added a dictionary extension method for getting or adding a new value via func 2019-09-10 17:18:12 -04:00
Chris Cameron
83bc344ab3 feat: Added an event that is raised when the system time is set 2019-09-10 17:17:09 -04:00
Chris Cameron
0821dcb3ca fix: Fixed a bug where CultureInfo was not being cloned correctly 2019-09-10 17:16:31 -04:00
Chris Cameron
b6f64bb9b2 Merge branch 'fix/ModulusRename' of Common/Utils into dev 2019-09-09 19:54:24 +00:00
Drew Tingen
6ae110a997 Merge remote-tracking branch 'origin/dev' into fix/ModulusRename 2019-09-09 15:38:56 -04:00
Chris Cameron
efdb48f2c3 Merge branch 'fix/programdata-path' of Common/Utils into ConnectPro_v1.4 2019-09-09 19:33:32 +00:00
Drew Tingen
9d02ee0022 fix: Fixing MathUtilsTest after rename 2019-09-09 15:33:31 -04:00
Austin Noska
8c0416f70e docs: updating changelog 2019-09-09 15:28:03 -04:00
Austin Noska
0f27d68edf fix: Net Standard: the Root Config Path is now ICD.Connect in the current environments ProgramData directory 2019-09-09 15:25:35 -04:00
Drew Tingen
f8fc68e08f chore: remarks explaining method name limitations 2019-09-09 15:17:32 -04:00
Drew Tingen
fc4ae67e40 chore: changelog slightly more specific 2019-09-09 15:16:23 -04:00
Drew Tingen
0f618198b5 fix: Rename "Mod" to "Modulus" to keep S+ from throwing a fit 2019-09-09 15:06:39 -04:00
Chris Cameron
9a6f197aa0 feat: Added TimeSpan extension methods for cycling hours and minutes without modifying the day 2019-09-09 10:07:08 -04:00
Chris Cameron
45ee3e70b0 feat: Added mod method to MathUtils 2019-09-09 10:06:08 -04:00
Chris Cameron
b09f614ef5 feat: Added a method for determining if a culture uses 24 hour format 2019-09-04 14:31:16 -04:00
Chris Cameron
027c9ffe82 refactor: Changed DateTime extension method to a simple util method 2019-09-04 14:30:45 -04:00
Chris Cameron
dc1b60e629 feat: Added an extension method for getting the hour in 12 hour format 2019-09-04 12:36:54 -04:00
Chris Cameron
091ad10068 test: Updating test framework version 2019-09-03 16:09:03 -04:00
Chris Cameron
71bb320057 chore: Updating changelog, incrementing minor version 2019-09-03 10:52:19 -04:00
Chris Cameron
e6b0fd5f7b Merge remote-tracking branch 'origin/feat/xml-array' into ConnectPro_v1.4 2019-09-03 10:27:42 -04:00
Chris Cameron
2a2bff2e92 Merge branch 'feat/uptime-utils' of Common/Utils into ConnectPro_v1.4 2019-09-03 14:02:26 +00:00
Austin Noska
9c07b3da04 docs: updating changelog 2019-08-30 17:21:17 -04:00
Austin Noska
438b3d48e4 feat: Implemented Processor Utils for Net Standard to get the system uptime and the program uptime. 2019-08-30 17:19:17 -04:00
Austin Noska
629ceec84e feat: Added Public API Property to get the program install date based on the creation date of core dll file for Net Standard and SimplSharp 2019-08-30 17:18:18 -04:00
Chris Cameron
bb41d59a4b feat: Adding methods for deserializing an XML array of items 2019-08-29 17:21:57 -04:00
Chris Cameron
c23d81e023 chore: Updating nuget packages 2019-08-29 14:13:55 -04:00
Chris Cameron
18abe78550 feat: Better handling of JSON DateTimes in Net Standard 2019-08-27 15:01:09 -04:00
Chris Cameron
f33218f7a6 chore: Updating nuget packages 2019-08-22 17:17:35 -04:00
Chris Cameron
4938dad882 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.4
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-08-22 10:42:57 -04:00
Chris Cameron
5900f5974b chore: Updating changelog, incrementing patch version 2019-08-22 10:41:00 -04:00
Drew Tingen
81f7eb9c66 Merge branch 'fix/ordered-dict' of Common/Utils into MetLife_v5.4.3 2019-08-22 14:30:40 +00:00
Chris Cameron
440c1c62f1 fix: Fixed a bug with the IcdOrderedDict index setter that was creating additional values 2019-08-22 10:17:32 -04:00
Chris Cameron
63b590a9ea feat: ToStringJsonConverter rethrows the inner exception for TargetInvocationExceptions 2019-08-20 15:40:01 -04:00
Chris Cameron
f8c88630fc fix: Fixed a bug where ANSI color encoded strings with percentages were being scrambled 2019-08-20 15:34:40 -04:00
Chris Cameron
3f1f9611ec chore: Updating changelog, incrementing minor version 2019-08-15 11:02:18 -04:00
Chris Cameron
47c611a0b4 Merge remote-tracking branch 'origin/MetLife_v5.4.3' into dev 2019-08-15 10:57:50 -04:00
Chris Cameron
e388f35efb Revert "fix: fix for logging deadlock, use mutexes, add logging for last message sent."
This reverts commit 7c238b9fef.
2019-08-15 10:56:34 -04:00
Jack Kanarish
89061b5cbf feat: add unit test for timer 2019-08-07 20:47:54 -04:00
Chris Cameron
ff6f15d3ef fix: Potential JSON under-read fix 2019-08-07 17:34:07 -04:00
Drew Tingen
02e6fe9f8c chore: formatting 2019-08-07 13:30:55 -04:00
Drew Tingen
edb5534b9d Merge remote-tracking branch 'origin/fix/json-dict' into KrangAtHome 2019-08-07 13:28:26 -04:00
Drew Tingen
6af3e5b2ff fix: Reflection - throw inner exception for parameterless constructors that throw exceptions 2019-08-07 13:28:11 -04:00
Chris Cameron
65f76402cc feat: Serializing both keys and values to JSON when serializing dicts 2019-08-07 13:02:18 -04:00
Chris Cameron
5700cf4ce2 feat: Re-adding missing util method for getting class attributes 2019-08-01 09:24:17 -04:00
Jack Kanarish
7c238b9fef fix: fix for logging deadlock, use mutexes, add logging for last message sent. 2019-07-31 16:22:05 -04:00
Laura Gomez
6eda848410 feat: Initial commit of EmailValidation class 2019-07-31 11:47:52 -04:00
Laura Gomez
7b44867f34 docs: updating changelog 2019-07-30 13:38:37 -04:00
Laura Gomez
149f480add fix: Fixing JSON datetime parsing in 2017 2019-07-30 12:16:29 -04:00
Austin Noska
0f5632ced8 refactor: changed public method to private as it is only being used from within EnumUtils 2019-07-18 11:37:33 -04:00
Chris Cameron
9df5f7ae37 feat: Clarifying method usage 2019-07-12 17:17:05 -04:00
Laura Gomez
6e056c9dcc feat: Added util extension method for converting a DateTime to a Unix timestamp 2019-07-12 13:57:52 -04:00
Chris Cameron
7add461a1a Merge branch 'feat/log-timestamps' of Common/Utils into ConnectPro_v1.3 2019-07-11 14:44:37 +00:00
Austin Noska
cb3677bd72 docs: updating changelog 2019-07-11 10:39:26 -04:00
Austin Noska
69ad4bb240 feat: Added timestamps to logs for non Simplsharp programs 2019-07-11 10:23:17 -04:00
Chris Cameron
1a868d5a7d chore: Updating changelog, incrementing minor version 2019-07-03 10:22:01 -04:00
Laura Gomez
bb6110931a feat : added a StartofDay and EndofDay DateTime methods. 2019-07-02 16:28:29 -04:00
Chris Cameron
909ebfbc97 fix: Throwing an exception when trying to read non-primitive JSON tokens as string 2019-07-01 17:07:50 -04:00
Chris Cameron
3d068aeb68 fix: Potential fix for errant '?' characters in URIs 2019-06-28 11:22:23 -04:00
Chris Cameron
1f6915a825 Merge branch 'feat/GetCliqueOptimization' of Common/Utils into ConnectPro_v1.3 2019-06-27 15:02:00 +00:00
Austin Noska
00e7fd6a6b docs: updating changelog 2019-06-27 11:00:03 -04:00
Austin Noska
e3f356a5db test: updating get cliques unit tests 2019-06-27 10:58:22 -04:00
Austin Noska
2d401959b6 feat: optimized get clique by using a bredth-first-search so it would not have to search the whole graph 2019-06-27 10:57:55 -04:00
Austin Noska
7cc5a47d6a feat: Added a hashset of visited nodes so bfs can be used on graphs 2019-06-27 10:57:00 -04:00
Chris Cameron
8c160c77c4 docs: Updating changelog 2019-06-26 13:33:37 -04:00
Austin Noska
65c50e8e90 feat: Added method to get a single clique given a starting node 2019-06-26 11:39:50 -04:00
Chris Cameron
3a2fc0eef7 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-24 12:52:24 -04:00
Chris Cameron
1be852685d chore: Updating changelog, incrementing minor version 2019-06-24 12:49:39 -04:00
Chris Cameron
6201184fab feat: IcdXmlException exposes LineNumber and LinePosition 2019-06-24 12:42:29 -04:00
Chris Cameron
e8acb42bb9 fix: Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder 2019-06-21 21:32:46 -04:00
Chris Cameron
d3d812265e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 16:54:12 -04:00
Chris Cameron
b915401109 chore: Updating changelog, incrementing patch version 2019-06-14 16:52:56 -04:00
Austin Noska
3e3a4e33cb fix: SafeTimer Stopped now returns a SafeTimer with no due time and no repeat period 2019-06-14 16:51:36 -04:00
Chris Cameron
b680bab67a Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 10:28:13 -04:00
Chris Cameron
7666021925 chore: Updating changelog, incrementing minor version 2019-06-14 10:25:47 -04:00
Chris Cameron
7b6092c291 fix: Fixing issues with Remap methods, added unit tests 2019-06-13 17:35:03 -04:00
Chris Cameron
f7740aaea2 fix: Fixing overflow 2019-06-13 17:10:34 -04:00
Chris Cameron
c31b2b556b feat: Adding methods for remapping and clamping numeric values to ranges 2019-06-13 16:56:49 -04:00
Chris Cameron
8866a3e1e6 fix: Fixing tests, bad maths 2019-06-13 11:59:12 -04:00
Chris Cameron
e3273934a7 fix: Begin rewriting RangeAttribute 2019-06-12 23:42:59 -04:00
Chris Cameron
0152259a25 chore: Updating changelog, incrementing minor version 2019-06-10 13:50:37 -04:00
Chris Cameron
98c3f17602 docs: Updating changelog 2019-06-10 13:50:23 -04:00
Chris Cameron
bb3fba100d fix: Fixing NetStandard CultureInfo database connection string 2019-06-10 13:48:08 -04:00
Chris Cameron
9adad373f6 fix: Better determine builtin cultures on NetStandard 2019-06-10 13:47:45 -04:00
Chris Cameron
844f8b7b46 refactor: Tidying 2019-06-10 13:47:21 -04:00
Chris Cameron
43d7ea944e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-06 15:54:04 -04:00
Chris Cameron
6526b2b811 chore: Updating changelog, incrementing minor version 2019-06-06 15:52:35 -04:00
Chris Cameron
ead365e251 chore: Fixing bad merge 2019-06-06 15:51:53 -04:00
Jack Kanarish
f24e6d2597 Merge branch 'feat/init-event' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
2019-06-06 11:06:09 -04:00
Chris Cameron
311f2dfaf4 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-05 15:03:33 -04:00
Chris Cameron
1c38d9f04a fix: Fixing Net Standard build, changing method name 2019-06-05 15:01:07 -04:00
Chris Cameron
02c18d152f chore: Updating changelog, incrementing patch version 2019-06-05 14:34:59 -04:00
Chris Cameron
fc482ec685 Merge branch 'fix/processorUptimeCaching' of Common/Utils into MetLife_v5.4.2 2019-06-05 18:28:28 +00:00
Austin Noska
d649fb9dc4 docs: updating utils changelog 2019-06-05 14:18:53 -04:00
Austin Noska
4d76abe046 fix: cache the uptime values and calculate the uptime from those values instead of polling the crestron processor each time its needed 2019-06-05 14:15:53 -04:00
Chris Cameron
d6d3bfa9e0 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-06-04 17:17:33 +00:00
Austin Noska
536742a1c6 docs: updating changelog 2019-06-04 12:54:39 -04:00
Austin Noska
dc824b2034 feat: Added a URI query builder 2019-06-04 12:19:12 -04:00
Chris Cameron
0cc588ce15 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-05-31 20:16:55 +00:00
Austin Noska
b996a295f6 Merge remote-tracking branch 'origin/ConnectPro_v1.3' into feat/XmlUtilsRoku
# Conflicts:
#	CHANGELOG.md
2019-05-31 16:14:14 -04:00
Austin Noska
4312ad1a61 chore: updated changelog 2019-05-31 15:58:06 -04:00
Austin Noska
7792b01629 feat: Added Shim to read a list from xml with no root element 2019-05-31 15:52:47 -04:00
Chris Cameron
4953e40f9e docs: Updating changelog 2019-05-31 13:34:29 -04:00
Chris Cameron
69f872ced1 feat: Adding features to IcdEnvironment for tracking program initialization state 2019-05-31 13:33:21 -04:00
Chris Cameron
7e3aef4cb3 fix: Fixed threading exception in TypeExtensions 2019-05-28 09:52:06 -04:00
Chris Cameron
a6fbd5a6d2 chore: Updating changelog 2019-05-28 09:51:54 -04:00
Chris Cameron
6f67064d34 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2 2019-05-24 09:59:54 -04:00
Chris Cameron
723759f805 Merge remote-tracking branch 'origin/MetLife_v5.4' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-24 09:59:07 -04:00
Chris Cameron
59f4411620 chore: Updating changelog, incrementing patch version 2019-05-24 09:55:48 -04:00
Chris Cameron
243e285948 feat: Added empty, placeholder interface for ICD Attributes 2019-05-24 09:55:33 -04:00
Chris Cameron
198bf8dac0 Merge branch 'fix/json-reader-extensions' of Common/Utils into ConnectPro_v1.3 2019-05-22 17:45:08 +00:00
Jeffery Thompson
78f5c4a7b6 fix: use ToString() instead of as string to support .NET Standard 2019-05-22 11:09:32 -04:00
Chris Cameron
c0ed7f9b26 feat: Clarifying neutral culture exception 2019-05-16 16:24:59 -04:00
Chris Cameron
6d08ee3bef Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
#	ICD.Common.Utils/PathUtils.cs
#	ICD.Common.Utils/ProcessorUtils.SimplSharp.cs
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-16 09:56:43 -04:00
Chris Cameron
2b376bff47 chore: Updating changelog, incrementing minor version 2019-05-15 15:59:09 -04:00
Chris Cameron
9f0e66e4a1 fix: XmlReaderExtensions handling both TimeSpan formats 2019-05-14 16:16:22 -04:00
Chris Cameron
4c93515f83 refactor: Exposing missing XmlConvert methods 2019-05-14 16:15:48 -04:00
Chris Cameron
9ad49540d2 fix: Fixing JSON converter error when handling default existing value with struct types 2019-05-10 16:04:11 -04:00
Chris Cameron
cbf7a3d79c chore: Updating changelog, incrementing minor version 2019-05-10 14:53:27 -04:00
Jeffery Thompson
5a4d3cabac Merge branch 'feat/localization' of Common/Utils into ConnectPro_v1.3 2019-05-10 18:35:34 +00:00
Jack Kanarish
dc0e65125a Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-05-10 12:06:13 -04:00
Chris Cameron
9d732ef4b2 feat: Adding RemoveRange method to IcdHashSet 2019-05-10 11:47:00 -04:00
Chris Cameron
ecdb4f4fb5 feat: AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization 2019-05-09 15:18:21 -04:00
Chris Cameron
6f5188909b fix: Fixing dumb mistake with extension method resolution order 2019-05-09 12:51:55 -04:00
Chris Cameron
3fa089b85e feat: Added methods for serializing additional types, arrays and dictionaries to JSON 2019-05-09 11:58:55 -04:00
Chris Cameron
fef667191b chore: Moving CultureInfo.sqlite into project root so it gets included in clz 2019-05-08 10:21:52 -04:00
Chris Cameron
28abb69c85 feat: Initial commit of IcdCultureInfo and associated CultureInfo.sqlite database 2019-05-07 11:52:13 -04:00
Chris Cameron
0bf88240b2 feat: Adding missing methods to sqlite wrappers 2019-05-07 11:51:08 -04:00
Drew Tingen
294afd1834 chore: update changelog 2019-05-02 20:22:54 -04:00
Drew Tingen
475f381991 feat: Breaking out Program/Common config directories from the full paths 2019-05-02 20:22:32 -04:00
Chris Cameron
1460bf2924 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
2019-05-02 10:28:09 -04:00
Chris Cameron
ab58ba721e chore: Updating changelog, incrementing patch version 2019-05-02 10:24:34 -04:00
Chris Cameron
d7bfb07c2c fix: Fixed PriorityQueue IndexOutOfRange exception when an inner queue becomes depleted 2019-05-02 10:23:53 -04:00
Chris Cameron
33b1d29781 fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 17:05:22 -04:00
Chris Cameron
78c20201ab fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 16:33:09 -04:00
Chris Cameron
66f4e797ed feat: Adding extension method for getting or adding a new item to a dictionary 2019-04-26 12:17:09 -04:00
Chris Cameron
94ac37b32a refactor: Tidying 2019-04-23 12:01:53 -04:00
Chris Cameron
22978e90c4 feat: Added extension method for peeking queues 2019-04-23 09:57:28 -04:00
Chris Cameron
995a57f8e4 chore: Updating changelog, incrementing minor version 2019-04-16 14:07:52 -04:00
Chris Cameron
d6d767d8f9 Merge remote-tracking branch 'origin/feat/logs' into ConnectPro_v1.2 2019-04-16 14:01:11 -04:00
Jack Kanarish
0931d6f1ec feat: add helper method for un-mapping a range from ushorts 2019-04-10 17:17:30 -04:00
Jack Kanarish
24859aaa31 feat: add types to maprange 2019-04-10 17:16:26 -04:00
Chris Cameron
798e9cc0a7 Merge branch 'feat/SPlusUtils' of Common/Utils into dev 2019-04-09 19:58:33 +00:00
Drew Tingen
1dac1bfb67 chore: Changelog + Docs 2019-04-09 15:57:10 -04:00
Drew Tingen
829c24b667 feat: Adding SPlusUtils to convert ushort's to int 2019-04-09 15:46:10 -04:00
Chris Cameron
715c198763 feat: Keeping paths as they were until we can agree on an approach going forwards 2019-04-08 17:00:10 -04:00
Chris Cameron
d8741773c5 refactor: Removing unused code 2019-04-08 16:38:01 -04:00
Chris Cameron
26b924dd48 feat: IcdStreamWriter exposes WriteLine(string) 2019-04-08 16:31:53 -04:00
Chris Cameron
8892e6e223 feat: Adding ProgramLogsPath to PathUtils 2019-04-08 15:48:05 -04:00
Chris Cameron
23afa8e025 feat: Windows and VC4 use Config directory for configuration 2019-04-08 15:47:52 -04:00
Chris Cameron
7d1cc3139f chore: Updating nuget packages 2019-04-08 14:00:47 -04:00
Chris Cameron
30ea6ced9e fix: Fixing bad merge 2019-04-08 10:59:37 -04:00
Chris Cameron
3041d0f402 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-04-08 10:55:52 -04:00
Chris Cameron
f4693df048 Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-04-05 14:31:59 -04:00
Chris Cameron
736c2aee33 chore: Updating changelog, incrementing patch version 2019-04-05 14:29:44 -04:00
Chris Cameron
40342e2d9e Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry 2019-04-03 16:23:52 -04:00
Chris Cameron
5756d9654b fix: Fixing FormatException when parsing some JSON DateTimes 2019-04-03 16:19:53 -04:00
Chris Cameron
b2ca43baf1 feat: Adding extension methods for writing properties to JSON 2019-04-02 16:37:18 -04:00
Chris Cameron
f36b9f7856 fix: Fixing format exception when parsing JSON DateTime with timezone info 2019-04-01 16:47:08 -04:00
Chris Cameron
bcf13ef972 perf: Optimizing object instantiation for default constructors 2019-04-01 14:16:56 -04:00
Chris Cameron
100b8e4753 fix: JsonReader GetValueAsString ignores token type 2019-04-01 12:27:06 -04:00
Chris Cameron
134ee85067 feat: Adding JsonReader extension to read current value as DateTime 2019-03-31 20:38:22 -04:00
Chris Cameron
c054a9d752 fix: Fixing argument exceptions when looking up LAN2 properties on a system without multiple network adapters 2019-03-28 10:36:04 -04:00
Chris Cameron
ef19e20d67 docs: Updating changelog 2019-03-27 11:24:35 -04:00
Chris Cameron
3fd344a308 fix: Adding missing methods to Net Standard 2019-03-27 10:49:29 -04:00
Chris Cameron
17e7f4d3c9 Merge remote-tracking branch 'origin/feat/seeded_guid' into Telemetry
# Conflicts:
#	ICD.Common.Utils/Attributes/RangeAttribute.cs
2019-03-26 11:58:07 -04:00
Chris Cameron
87d1f4da16 feat: Added util method for generating seeded guids 2019-03-26 11:28:59 -04:00
Chris Cameron
88a4801f8e feat: Added extension method for generating stable string hashcodes 2019-03-26 11:28:15 -04:00
Jack Kanarish
c55e35ac6e Saftey commit for CC 2019-03-25 13:51:29 -04:00
Chris Cameron
24601b0ef2 fix: Potential fix for sqlite database locked exception 2019-03-14 16:31:13 -04:00
Chris Cameron
4fa46ff5a0 Merge remote-tracking branch 'origin/fix/VC4_Fixes' into ConnectPro_v1.2 2019-03-13 16:28:18 -04:00
Chris Cameron
827ab2cd42 refactor: Removing unused code, loosening attribute type constraints 2019-03-13 16:26:53 -04:00
Drew Tingen
158c261d19 fix: VC4 Compat Fixes 2019-03-09 14:51:44 -05:00
Chris Cameron
c607d1254e chore: Updating changelog, incrementing minor version 2019-03-01 14:48:57 -05:00
Chris Cameron
e90914664f Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.2 2019-03-01 14:32:25 -05:00
Chris Cameron
fc855d407b Merge remote-tracking branch 'origin/fix/IcdConsole' into ConnectPro_v1.2 2019-03-01 14:32:13 -05:00
Chris Cameron
e3a4713b3b fix: Fixed bug preventing deserialization of XML lists 2019-03-01 14:29:46 -05:00
Drew Tingen
f85896e947 fix: PrintLine raises OnConoslePrint, Crestron Console Response uses PrintLine, Better environment checks 2019-02-24 16:19:03 -05:00
Chris Cameron
131e2f87f4 feat: Adding constructor to BiDictionary to build from an existing dict 2019-02-21 14:04:06 -05:00
Chris Cameron
4a330637a7 feat: Type IsAssignableTo extension shim 2019-02-19 14:32:32 -05:00
Chris Cameron
fa124a0afc refactor: Resolving warning 2019-02-11 12:13:56 -05:00
Chris Cameron
72fd823643 test: Fixing unit tests 2019-02-07 17:13:25 -05:00
Chris Cameron
644388edad chore: Updating changelog, incrementing minor version 2019-02-07 16:55:22 -05:00
Chris Cameron
cbb05c8b79 refactor: Removing unused code 2019-02-07 16:53:33 -05:00
Chris Cameron
066c9f93a7 chore: Updating AssemblyInfo 2019-02-07 15:32:49 -05:00
Chris Cameron
9aa7459b0f chore: Updating changelog 2019-02-07 14:42:22 -05:00
Jack Kanarish
7557e01c9f feat: add processor utilities and environment utilities for telemetry 2019-02-07 10:45:06 -05:00
Chris Cameron
f8a813c97b perf: Removing redundant code, logging micro-optimization 2019-02-07 10:37:35 -05:00
Chris Cameron
be6a6de65a perf: ReprBuilder micro-optimizations 2019-02-06 17:09:37 -05:00
Chris Cameron
ffe3e67241 perf: Better JSON serialization of nullable types 2019-02-06 13:10:52 -05:00
Chris Cameron
141d911eb0 perf: Reduced size of JSON serialized nullable types 2019-02-06 11:31:14 -05:00
Chris Cameron
d6abf3fdf6 perf: Don't serialize namespace for builtin types 2019-02-04 13:22:59 -05:00
Chris Cameron
46a1ea09b6 refactor: Moving JSON type name util into TypeExtensions 2019-02-04 12:03:15 -05:00
Chris Cameron
2dc705d335 perf: Significantly reducing the size of JSON serialized types 2019-02-04 11:38:39 -05:00
Chris Cameron
0700a357dd feat: Adding ToStringJsonConverter 2019-02-01 14:52:33 -05:00
Chris Cameron
5fb7636ed4 feat: Extension method for reading JSON token as a Guid 2019-01-30 10:52:44 -05:00
Chris Cameron
196c2a535a feat: Added shims for ReflectionUtils.SubscribeEvent for known callbacks 2019-01-29 21:59:10 -05:00
Chris Cameron
db50ada952 refactor: Tidying 2019-01-29 17:49:23 -05:00
Chris Cameron
087b04fd62 chore: Updating changelog, incrementing major version 2019-01-29 14:52:36 -05:00
Chris Cameron
ea73351d39 refactor: Removing redundant critical section, support for chaining TableBuilder methods 2019-01-28 16:58:21 -05:00
Chris Cameron
ca1fae29b0 chore: Updating nuget packages 2019-01-28 14:19:38 -05:00
Chris Cameron
1916c2b750 refactor: Reducing duplicate code 2019-01-28 14:02:16 -05:00
Chris Cameron
3af2544e70 feat: ReprBuilder better supports method chaining 2019-01-28 13:32:35 -05:00
Chris Cameron
20e8aa93f2 Merge branch 'feat/ConsoleOnPrint' of Common/Utils into dev 2019-01-28 13:04:40 +00:00
Drew Tingen
3937902f38 Merge remote-tracking branch 'origin/dev' into feat/ConsoleOnPrint
# Conflicts:
#	CHANGELOG.md
2019-01-27 22:59:25 -08:00
Drew Tingen
021d5781a3 Merge branch 'feat/json' of Common/Utils into dev 2019-01-28 06:56:15 +00:00
Drew Tingen
b429e4bc53 feat: OnConsolePrint event and better VC-4 console support 2019-01-27 22:55:24 -08:00
Chris Cameron
4a203e2449 refactor: Reducing duplicate code 2019-01-27 17:55:47 -05:00
Chris Cameron
d41203b856 docs: Updating changelog 2019-01-25 17:11:08 -05:00
Chris Cameron
2f21379e52 Merge remote-tracking branch 'origin/dev' into feat/json 2019-01-25 17:10:03 -05:00
Chris Cameron
f60de4321b chore: Updating changelog, incrementing minor version 2019-01-25 17:07:05 -05:00
Chris Cameron
bd2ea606ae docs: Updating changelog 2019-01-25 16:52:09 -05:00
Chris Cameron
1f20c07e94 refactor: Splitting JSON extensions into Reader and Writer extensions, removing unused code 2019-01-25 14:06:51 -05:00
Chris Cameron
1be588b86a refactor: Simplifying JSON converters 2019-01-25 13:57:41 -05:00
Chris Cameron
488df297fc refactor: Removing unused code 2019-01-25 13:57:19 -05:00
Chris Cameron
80a4d94358 refactor: Removing unused code 2019-01-24 17:28:59 -05:00
Chris Cameron
6a40f3ce18 refactor: Tidying 2019-01-24 16:46:07 -05:00
Chris Cameron
d564a0a423 feat: Adding shorthand method for serializing an object into a JSON message 2019-01-24 16:21:29 -05:00
Chris Cameron
a9a544c433 feat: Simplifying generic JSON converters 2019-01-24 15:58:46 -05:00
Chris Cameron
2e0837f5c8 feat: Extension methods for reading current JSON token to the given type 2019-01-24 15:58:21 -05:00
Chris Cameron
77be0ec477 refactor: Removing unused code 2019-01-24 15:57:53 -05:00
Chris Cameron
524cdc3e31 feat: EventArgs constructor overloads 2019-01-24 11:57:39 -05:00
Chris Cameron
1d6e8d55ca refactor: Tidying 2019-01-23 11:10:35 -05:00
Chris Cameron
3ba5f11587 Merge branch 'feat/VC-4' of Common/Utils into MetLife_v5.4 2019-01-22 17:51:47 +00:00
Drew Tingen
fb7a6e27b8 chore: update changelog 2019-01-22 09:50:42 -08:00
Drew Tingen
fffc8e4a60 fix: Fixed GetApplicationRootDirectory for NetStandard 2019-01-22 09:50:32 -08:00
Drew Tingen
1d7ada87c5 refactor: Removing preprocessors and adding better multi-platform support 2019-01-22 09:47:20 -08:00
Drew Tingen
3a4438ec1e chore: update changelog 2019-01-22 09:24:37 -08:00
Drew Tingen
21ce86de0f fix: Use IcdEnvironment instead of CrestronEnvironment 2019-01-22 09:24:25 -08:00
Drew Tingen
3cb29452a2 chore: tidying 2019-01-22 09:17:35 -08:00
Drew Tingen
114a5e4ec7 Merge remote-tracking branch 'origin/dev' into feat/VC-4 2019-01-22 09:13:06 -08:00
Drew Tingen
a9d411dcfd feat: Path support for VC-4 2019-01-22 09:11:48 -08:00
Chris Cameron
e708ef9603 fix: Fix for potential memory leak with timers 2019-01-21 11:49:21 -05:00
Drew Tingen
aae4fb6185 Merge branch 'feat/mono' of Common/Utils into dev 2019-01-17 23:12:09 +00:00
Chris Cameron
8401ab1852 feat: Added SimplSharpProMono to eRuntimeEnvironment enum 2019-01-17 17:15:34 -05:00
Chris Cameron
27760f2282 fix: Resolving warning 2019-01-14 16:42:32 -05:00
Chris Cameron
80a0ca26c5 chore: Updating changelog, incrementing minor version 2019-01-10 16:11:00 -05:00
Chris Cameron
b9ec2f3222 refactor: Tidying 2019-01-10 10:45:53 -05:00
Chris Cameron
a6ad52d492 refactor: Removing log from ReflectionUtils.CreateInstance, doesn't make sense here 2019-01-10 10:25:46 -05:00
Jack Kanarish
64e11db0bc Merge branch 'MetLife_v5.4' of https://cs-gogs.icdpf.net/Common/Utils into MetLife_v5.4 2019-01-10 09:53:03 -05:00
Jack Kanarish
d01e9345d5 feat: add range attribute, which describes the valid ranges of a property if that range doesnt match the range of the datatype 2019-01-10 09:52:54 -05:00
Chris Cameron
466dc6deb5 fix: Fixing bug where xml fragments were being written with prepended document info 2019-01-09 16:33:33 -05:00
Chris Cameron
ad47c890a8 refactor: Tidying 2019-01-08 14:47:03 -05:00
Chris Cameron
108317212c feat: Adding TryGetPortForScheme method to UriExtensions 2019-01-07 15:37:33 -05:00
Chris Cameron
4a411e8990 refactor: Removing unused code 2019-01-07 12:20:13 -05:00
Chris Cameron
4cd28a8a12 fix: IcdHashSet preserves comparer when an operation creates a new IcdHashSet 2019-01-03 13:03:51 -05:00
Chris Cameron
470c35cab7 chore: Updating changelog, incrementing minor version 2019-01-02 14:18:42 -05:00
Chris Cameron
a372d97868 feat: Adding RegexUtils shims for RegexOptions 2018-12-19 07:50:23 -05:00
Chris Cameron
f208ec521b feat: Added RegexUtils method for replacing a single group in a match 2018-12-19 06:40:39 -05:00
Jack Kanarish
347cf70b6c Merge branch 'MetLife_v5.4' of https://cs-gogs.icdpf.net/Common/Utils into MetLife_v5.4 2018-12-17 09:34:47 -05:00
Jack Kanarish
1076795fae refactor: make isenumtype public for use in other classes 2018-12-17 09:34:37 -05:00
Chris Cameron
7d059bc605 Merge remote-tracking branch 'origin/dev' into MetLife_v5.4 2018-12-10 11:37:15 -05:00
Chris Cameron
dd270adf9e feat: Added methods to IcdUriBuilder for appending path 2018-12-10 11:36:31 -05:00
Jack Kanarish
efb5e014ec feat: give better information when constructor lookup fails 2018-12-04 14:36:04 -05:00
Chris Cameron
083280cc64 chore: Updating changelog 2018-12-03 14:32:21 -05:00
Rashod Davis
e222ce424b feat: Adding short parsing methods to XML utils 2018-12-03 10:32:39 -05:00
Rashod Davis
ad7176506d feat: Added GetAttributeAsEnum xml utils method 2018-12-03 10:32:16 -05:00
Chris Cameron
e4e3e9b91a feat: IcdUriBuilder better supports null Uris 2018-11-28 13:28:40 -05:00
Chris Cameron
1721116908 chore: Removing bad null reference warning 2018-11-27 12:17:29 -05:00
Chris Cameron
d8489d31b6 chore: Updating changelog, incrementing major version 2018-11-20 14:59:21 -05:00
Chris Cameron
a8552ea0e3 chore: Adding xml encoding headers 2018-11-20 14:05:08 -05:00
Chris Cameron
e700650735 Merge remote-tracking branch 'origin/MetLife_v5.2' into MetLife_v5.4 2018-11-20 13:25:40 -05:00
Chris Cameron
ed9c017856 Merge branch 'fix/console-print' of Common/Utils into dev 2018-11-16 22:22:02 +00:00
Jeffery Thompson
0ee1b440ee fix: exception in NetStandard if console message contained curly braces 2018-11-16 17:19:49 -05:00
Chris Cameron
4184f85826 chore: Updating test framework sdk 2018-11-14 15:48:17 -05:00
Chris Cameron
42cc8c2cfc feat: Adding string extension method for removing all instances of a given string, fixes unexpected use of Remove characters method 2018-11-12 10:37:16 -05:00
Drew Tingen
6b37db3530 Merge branch 'fix/csv-nullref' of Common/Utils into dev 2018-11-09 21:09:50 +00:00
Chris Cameron
ad8fa216a5 fix: Fixed NullReferenceException when writing null strings to CSV 2018-11-09 16:08:25 -05:00
Chris Cameron
ef415bb20f fix: Removing default fragment xml conformance level, fixes StartDocument on net standard 2018-11-09 14:59:22 -05:00
Chris Cameron
fe614ae8ad chore: Updating .csproj 2018-11-09 13:40:54 -05:00
Chris Cameron
2d4bc57ed8 feat: Reworked xml attribute utils for performance 2018-11-09 11:42:36 -05:00
Chris Cameron
c048c4fc65 test: Adding test case for RemoveCharacters string extension method 2018-11-09 10:09:40 -05:00
Chris Cameron
2e2eebd95f chore: Updating changelog, incrementing minor version 2018-11-08 16:25:05 -05:00
Chris Cameron
e21830a7d5 perf: Moving enumerable extensions optimizations into correct place 2018-11-08 16:15:22 -05:00
Chris Cameron
f53607018c refactor: Enumerate over XML attributes 2018-11-08 15:50:12 -05:00
Chris Cameron
e0176741d2 fix: Fixing dumb mistake in TryFirst and TryLast extensions 2018-11-08 15:49:44 -05:00
Chris Cameron
742b7e99aa feat: Adding method for getting properties with a given attribute type 2018-11-08 13:03:23 -05:00
Chris Cameron
cf0c71d39b refactor: Removing redundant generic constraints 2018-11-08 13:02:49 -05:00
Chris Cameron
376f9c0837 refactor: Removing unused code 2018-11-08 11:46:14 -05:00
Chris Cameron
8b1c53ebe1 feat: IcdXmlTextWriter exposes WriteStartDocument and WriteEndDocument 2018-11-07 14:25:24 -05:00
Chris Cameron
2e0b0da87f chore: Updating test SDK 2018-11-07 12:57:35 -05:00
Chris Cameron
8311fe5c9d perf: Micro-optimization 2018-11-06 15:45:43 -05:00
Chris Cameron
fb41d76a9c docs: Clarifying method usages 2018-11-06 15:45:34 -05:00
Chris Cameron
8f107aa209 Merge remote-tracking branch 'origin/MetLife_v5.4' into ConnectPro_v1.1 2018-11-06 13:25:17 -05:00
Jack Kanarish
2024dc0171 fix: remove constraint 2018-11-06 13:06:39 -05:00
Chris Cameron
923866dbdf feat: Validation 2018-11-02 16:28:05 -04:00
Chris Cameron
a14b4a5803 refactor: Tidying 2018-11-02 14:03:13 -04:00
Chris Cameron
fac2610b83 Merge remote-tracking branch 'origin/MetLife_v5.4' into ConnectPro_v1.1 2018-11-02 11:29:28 -04:00
Jack Kanarish
0ef0286a9f Merge remote-tracking branch 'origin/dev' into MetLife_v5.4 2018-11-02 10:46:19 -04:00
Jack Kanarish
d084553600 fix: fix an issue where use of except causes phone numbers with repeat digits to be improperly truncated 2018-11-01 17:28:27 -04:00
Chris Cameron
2b14a6b65c refactor: Tidying 2018-10-30 17:20:52 -04:00
Chris Cameron
043a50669a perf: Small optimization in StringExtensions 2018-10-30 17:06:42 -04:00
Chris Cameron
b58220d3c7 perf: Small enumerable optimizations 2018-10-30 16:13:48 -04:00
Chris Cameron
03de74a494 perf: Potential performance improvement when comparing enumerables 2018-10-30 13:47:08 -04:00
104 changed files with 5551 additions and 1793 deletions

View File

@@ -6,6 +6,207 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
## [9.9.0] - 2019-09-16
### Added
- Added a method for converting 24 hour to 12 hour format
- Added a method for determining if a culture uses 24 hour format
- Added math util method for modulus
- Added TimeSpan extension methods for cycling hours and minutes without modifying the day
- Added a dictionary extension method for getting or adding a new value via func
- Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting
- Added environment methods for setting the current date and time
- Added BinarySearch extension method for all IList types
- Added PathUtils methods to get ProgramData directory
### Changed
- The Root Config path in Net Standard will now be the ICD.Connect folder in the current environments ProgramData directory
- Fixed a bug where CultureInfo was not being cloned correctly
- List AddSorted extensions now work for all IList types
## [9.8.0] - 2019-09-03
### Added
- Added Public API Properties to get the program install date based on the creation date of core dll file for NetStandard and SimplSharp
- Implemented processor utils for NetStandard to get the system uptime and the program uptime
- Added methods for deserializing an XML array
### Changed
- Fixed a bug where ANSI color encoded strings with percentages were being scrambled
- Improvements to JSON DateTime parsing, particularly in Net Standard
## [9.7.0] - 2019-08-15
### Added
- Added logger timestamps to non simplsharp programs
- Added Net Standard Support for JSON DateTime formats
- Added EmailValidation class
### Changed
- JSON dict serialization serializes keys instead of converting to property name
## [9.6.0] - 2019-07-03
### Added
- Added RecursionUtils method to get a single clique given a starting node
- Breadth First Search can now search graphs in addition to trees
- Added StartOfDay and EndOfDay DateTime extension methods
### Changed
- Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder
- Throwing an exception when attempting to read a non-primitive JSON token as a string
## [9.5.0] - 2019-06-10
### Added
- Added Shim to read a list from xml with no root element
- Added a URI query builder
### Changed
- Fixed JSON DateTime parsing in .Net Standard
- Fixed threading exception in TypeExtensions
- Fixes for platform-agnostic culture handling
## [9.4.0] - 2019-05-10
### Added
- Added extension method for peeking queues
- Added extension method for getting or adding a new item to a dictionary
- Added methods for serializing additional types, arrays and dictionaries to JSON
- AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization
- Added RemoveRange method to IcdHashSet
- Added IcdCultureInfo and CultureInfo database for localization
### Changed
- IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost"
## [9.3.0] - 2019-04-16
### Added
- Added SPlusUtils with ConvertToInt method taking LowWord/HighWord ushorts
- Added JsonReader extension methods for reading DateTimes
- Added JsonReader extension methods for writing properties
- IcdStreamWriter exposes WriteLine(string)
- Added ProgramLogsPath to PathUtils
### Changed
- Fixes for VC4 compatibility
- Fixed JSON DateTime parsing for timezone information
- Small reflection optimizations
## [9.2.0] - 2019-03-01
### Added
- Added Type IsAssignableTo extension shim
- Added constructor to BiDictionary to instantiate from an existing dict
### Changed
- Fixed bug preventing deserialization of XML lists
- Crestron ConsoleResponse uses PrintLine instead of Print
- Use PrintLine instead of ConsoleResponse on Crestron server
## [9.1.0] - 2019-02-07
### Added
- Added SubscribeEvent shim for delegate callbacks
- Extension method for reading JSON token as a GUID
- Added ToStringJsonConverter
### Changed
- Significantly reduced size of JSON serialized Types
- Small logging optimizations
## [9.0.0] - 2019-01-29
### Added
- IcdConsole.OnConsolePrint event
### Changed
- Better VC-4 support for IcdConsole
- JSON refactoring for simpler deserialization
## [8.7.1] - 2019-08-22
### Changed
- Fixed a bug with the IcdOrderedDict index setter that was creating additional values
## [8.7.0] - 2019-06-24
### Added
- IcdXmlException exposes line number and position properties
## [8.6.1] - 2019-06-14
### Changed
- Fixed a bug where stopped timers on NetStandard would still have a periodic callback duration
## [8.6.0] - 2019-06-14
### Changed
- Overhaul of RangeAttribute remap methods to better avoid overflows
## [8.5.0] - 2019-06-06
### Added
- Adding features to IcdEnvironment for tracking program initialization state
## [8.4.1] - 2019-06-05
### Changed
- Caching the program/processor start time and calculating the uptime from those values instead of polling the crestron processor
## [8.4.0] - 2019-05-15
### Added
- Added GUID utils for generating seeded GUIDs
- Added extension method for getting stable hashcodes from strings
- Added environment and processor utilities for determining DNS status and hostname
### Changed
- RangeAttribute improvements for better type safety
- PathUtils breaking out ProgramConfigDirectory and CommonConfigDirectory from the full paths
## [8.3.3] - 2019-05-24
### Added
- Added empty, placeholder interface for ICD Attributes
## [8.3.2] - 2019-05-02
### Changed
- Fixed PriorityQueue IndexOutOfRange exception when an inner queue becomes depleted
## [8.3.1] - 2019-04-05
### Changed
- Fixed FormatException when parsing some JSON DateTimes
## [8.3.0] - 2019-01-25
### Added
- Added SimplSharpProMono to eRuntimeEnvironment enum
- Added path support for SimplSharpProMono environment
- Added GetApplicationRootDirectory for all platforms
### Changed
- Small fixes for better VC4 support
## [8.2.0] - 2019-01-10
### Added
- Added TryGetPortForScheme method to UriExtensions
- Added range attribute for clarifying numeric fields, properties and parameters
### Changed
- IcdHashSet preserves comparer when an operation creates a new IcdHashSet
- Fixed bug where XML fragments on Net Standard were being prepended with a document header
## [8.1.0] - 2019-01-02
### Added
- Added GetAttributeAsEnum xml utils method
- Adding short parsing methods to XML utils
- Added methods to IcdUriBuilder for appending path
- Added RegexUtils method for replacing a single group in a match
## [8.0.0] - 2018-11-20
### Added
- XML TryGetAttribute methods
### Changed
- Performance improvements when working with xml attributes
- Fixed NullReferenceException when writing null strings to CSV
- Fixed bug with string formatting console input on Net Standard
### Removed
- Removed IcdXmlAttribute
## [7.1.0] - 2018-11-08
### Added
- IcdXmlTextWriter exposes WriteStartDocument and WriteEndDocument
- AttributeUtils method for getting properties with the given attribute type
### Changed
- EnumerableExtensions performance improvements
- Fixed bug in StringExtensions when removing a sequence of characters from a string
## [7.0.0] - 2018-10-30
### Changed
- Micro-optimizations in string and XML manipulations

View File

@@ -0,0 +1,86 @@
using System;
using NUnit.Framework;
using RangeAttribute = ICD.Common.Utils.Attributes.RangeAttribute;
namespace ICD.Common.Utils.Tests.Attributes
{
[TestFixture]
public sealed class RangeAttributeTest : AbstractIcdAttributeTest<RangeAttribute>
{
#region Properties
[TestCase(1)]
[TestCase(1.0f)]
[TestCase(1.0)]
public void MinTest(object min)
{
Assert.AreEqual(min, new RangeAttribute(min, min).Min);
}
[TestCase(1)]
[TestCase(1.0f)]
[TestCase(1.0)]
public void MaxTest(object max)
{
Assert.AreEqual(max, new RangeAttribute(max, max).Max);
}
#endregion
#region Methods
[TestCase((double)0, (double)0)]
[TestCase((double)1, (double)1)]
[TestCase(ushort.MaxValue, double.MaxValue)]
[TestCase(short.MinValue, double.MinValue)]
public void RemapToDoubleTest(object value, double expected)
{
Assert.AreEqual(expected, RangeAttribute.RemapToDouble(value));
}
[TestCase((double)0, typeof(ushort), (ushort)32767)]
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
public void RemapFromDoubleTest(double value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.RemapFromDouble(value, type));
}
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(short.MaxValue, typeof(ushort), short.MaxValue)]
public static void Clamp(object value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
}
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
public void Clamp(double value, Type type, double expected)
{
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
}
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
[TestCase(short.MaxValue, typeof(ushort), ushort.MaxValue)]
public void RemapTest(object value, Type type, object expected)
{
Assert.AreEqual(expected, RangeAttribute.Remap(value, type));
}
[TestCase(0, 100, ushort.MaxValue, typeof(ushort), ushort.MaxValue)]
[TestCase(0, 100, ushort.MaxValue, typeof(short), short.MaxValue)]
public void ClampMinMaxThenRemapTest(object min, object max, object value, Type type, object expected)
{
Assert.AreEqual(expected, new RangeAttribute(min, max).ClampMinMaxThenRemap(value, type));
}
[TestCase(0, 100, ushort.MaxValue, 100)]
[TestCase(0, 100, ushort.MinValue, 0)]
public void RemapMinMaxTest(object min, object max, object value, object expected)
{
Assert.AreEqual(expected, new RangeAttribute(min, max).RemapMinMax(value));
}
#endregion
}
}

View File

@@ -1,90 +0,0 @@
using System.Collections.Generic;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.EventArguments;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Collections
{
[TestFixture]
public sealed class AsyncEventQueueTest
{
[Test]
public void ItemDequeuedFeedbackTest()
{
Assert.Inconclusive();
}
[Test]
public void CountTest()
{
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
{
queue.OnItemDequeued +=
(sender, args) =>
{
ThreadingUtils.Sleep(200);
};
Assert.AreEqual(0, queue.Count);
for (int index = 0; index < 5; index++)
queue.Enqueue(index);
Assert.AreEqual(5, queue.Count);
}
}
[Test]
public void EnqueueTest()
{
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
{
List<GenericEventArgs<int>> eventArgs = new List<GenericEventArgs<int>>();
queue.OnItemDequeued +=
(sender, args) =>
{
eventArgs.Add(args);
};
Assert.AreEqual(0, eventArgs.Count);
for (int index = 0; index < 5; index++)
queue.Enqueue(index);
ThreadingUtils.Sleep(500);
Assert.AreEqual(5, eventArgs.Count);
Assert.AreEqual(0, eventArgs[0].Data);
Assert.AreEqual(1, eventArgs[1].Data);
Assert.AreEqual(2, eventArgs[2].Data);
Assert.AreEqual(3, eventArgs[3].Data);
Assert.AreEqual(4, eventArgs[4].Data);
}
}
[Test]
public void ClearTest()
{
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
{
queue.OnItemDequeued +=
(sender, args) =>
{
ThreadingUtils.Sleep(200);
};
Assert.AreEqual(0, queue.Count);
for (int index = 0; index < 5; index++)
queue.Enqueue(index);
Assert.AreEqual(5, queue.Count);
queue.Clear();
Assert.AreEqual(0, queue.Count);
}
}
}
}

View File

@@ -69,16 +69,26 @@ namespace ICD.Common.Utils.Tests.Collections
[Test]
public void IndexerTest()
{
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
{
{0, 0},
{1, 10},
{-1, -10}
};
// ReSharper disable UseObjectOrCollectionInitializer
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>();
// ReSharper restore UseObjectOrCollectionInitializer
dict[0] = 0;
dict[1] = 10;
dict[-1] = -10;
dict[-1] = -11;
Assert.AreEqual(0, dict[0]);
Assert.AreEqual(10, dict[1]);
Assert.AreEqual(-10, dict[-1]);
Assert.AreEqual(-11, dict[-1]);
Assert.AreEqual(3, dict.Count);
int[] expectedKeys = {-1, 0, 1 };
int[] expectedValues = {-11, 0, 10};
Assert.AreEqual(expectedKeys, dict.Keys.ToArray());
Assert.AreEqual(expectedValues, dict.Values.ToArray());
}
#endregion

View File

@@ -168,6 +168,29 @@ namespace ICD.Common.Utils.Tests.Collections
Assert.AreEqual(0, queue.Count);
}
[Test]
public void TryDequeueTest()
{
PriorityQueue<int> queue = new PriorityQueue<int>();
queue.Enqueue(10, 1);
queue.Enqueue(20, 2);
queue.Enqueue(30, 3);
int output;
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(10, output);
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(20, output);
Assert.IsTrue(queue.TryDequeue(out output));
Assert.AreEqual(30, output);
Assert.IsFalse(queue.TryDequeue(out output));
Assert.AreEqual(0, output);
}
[Test]
public void GetEnumeratorTest()
{

View File

@@ -0,0 +1,17 @@
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class DateTimeUtilsTest
{
[TestCase(1, 1)]
[TestCase(0, 12)]
[TestCase(12, 12)]
[TestCase(23, 11)]
public void To12HourTest(int hour, int expected)
{
Assert.AreEqual(expected, DateTimeUtils.To12Hour(hour));
}
}
}

View File

@@ -3,16 +3,16 @@
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class DateTimeExtensionsTest
{
[Test]
public static void ToShortTimeStringTest()
{
Assert.Inconclusive();
}
public sealed class DateTimeExtensionsTest
{
[Test]
public void ToShortTimeStringTest()
{
Assert.Inconclusive();
}
[Test]
public static void ToLongTimeStringWithMillisecondsTest()
public void ToLongTimeStringWithMillisecondsTest()
{
Assert.Inconclusive();
}

View File

@@ -335,9 +335,9 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void ToDictionaryIntTest()
public void ToIndexedDictionaryTest()
{
Dictionary<int, int> values = new[] {1, 2, 3}.ToDictionary();
Dictionary<int, int> values = new[] {1, 2, 3}.ToIndexedDictionary();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(1, values[0]);
@@ -346,9 +346,9 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void ToDictionaryUIntTest()
public void ToIndexedDictionaryUIntTest()
{
Dictionary<uint, int> values = new[] {1, 2, 3}.ToDictionaryUInt();
Dictionary<uint, int> values = new[] {1, 2, 3}.ToIndexedDictionaryUInt();
Assert.AreEqual(3, values.Count);
Assert.AreEqual(1, values[0]);

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Text;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
using Newtonsoft.Json;
using NUnit.Framework;
@@ -17,6 +18,36 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.Inconclusive();
}
[Test]
public void ReadObjectTest()
{
const string json =
"{\"name\":\"Test\",\"help\":\"Test test.\",\"type\":\"System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\",\"value\":\"Test\"}";
Dictionary<string, string> expected = new Dictionary<string, string>
{
{"name", "Test"},
{"help", "Test test."},
{"type", "System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"},
{"value", "Test"}
};
Dictionary<string, string> deserialized = new Dictionary<string, string>();
using (IcdStringReader textReader = new IcdStringReader(json))
{
using (JsonReader reader = new JsonTextReader(textReader.WrappedTextReader))
{
JsonSerializer serializer = new JsonSerializer();
reader.Read();
reader.ReadObject(serializer, (p, r, s) => deserialized.Add(p, (string)r.Value));
}
}
Assert.IsTrue(deserialized.DictionaryEqual(expected));
}
[Test]
public void GetValueAsIntTest()
{
@@ -78,53 +109,5 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.IsTrue(deserialized.SequenceEqual(new[] {1, 2, 3, 4}));
}
[Test]
public void SerializeDictionaryTest()
{
Dictionary<int, string> dict = new Dictionary<int, string>
{
{1, "Item 1"},
{10, "Item 2"},
{15, "Item 3"}
};
JsonSerializer serializer = new JsonSerializer();
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
serializer.SerializeDictionary(writer, dict);
}
}
string json = stringBuilder.ToString();
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
}
[Test]
public void DeserializeDictionaryTest()
{
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
JsonSerializer serializer = new JsonSerializer();
Dictionary<int, string> deserialized;
using (StringReader stringReader = new StringReader(json))
{
using (JsonReader reader = new JsonTextReader(stringReader))
{
reader.Read();
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
}
}
Assert.AreEqual(3, deserialized.Count);
Assert.AreEqual("Item 1", deserialized[1]);
Assert.AreEqual("Item 2", deserialized[10]);
Assert.AreEqual("Item 3", deserialized[15]);
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
@@ -43,82 +42,6 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(1, testList[3]);
}
[Test]
public void PadRightTest()
{
List<int> testList = new List<int>();
testList.PadRight(10);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(0, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(10);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(15, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(1);
Assert.AreEqual(5, testList.Count);
Assert.AreEqual(15, testList.Sum());
}
[Test]
public void PadRightDefaultTest()
{
List<int> testList = new List<int>();
testList.PadRight(10, 1);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(10, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(10, 1);
Assert.AreEqual(10, testList.Count);
Assert.AreEqual(20, testList.Sum());
testList = new List<int>
{
1,
2,
3,
4,
5
};
testList.PadRight(1, 1);
Assert.AreEqual(5, testList.Count);
Assert.AreEqual(15, testList.Sum());
}
private sealed class InverseComparer : IComparer<int>
{
public int Compare(int x, int y)

View File

@@ -1,73 +1,82 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class StringExtensionsTest
{
[Test]
public void IndexOfTest()
{
string first;
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] { "test2", "test3" }, out first));
Assert.AreEqual("test3", first);
}
[TestFixture]
public sealed class StringExtensionsTest
{
[Test]
public void IndexOfTest()
{
string first;
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] {"test2", "test3"}, out first));
Assert.AreEqual("test3", first);
}
[TestCase(true, "12345", '1')]
[TestCase(false, "12345", '2')]
public void StartsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.StartsWith(character));
}
[TestCase(true, "12345", '1')]
[TestCase(false, "12345", '2')]
public void StartsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.StartsWith(character));
}
[TestCase(true, "12345", '5')]
[TestCase(false, "12345", '2')]
public void EndsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.EndsWith(character));
}
[TestCase(true, "12345", '5')]
[TestCase(false, "12345", '2')]
public void EndsWithTest(bool expected, string value, char character)
{
Assert.AreEqual(expected, value.EndsWith(character));
}
[Test]
public void SplitCharCountTest()
{
string[] split = "123-456-789-0".Split('-', 2).ToArray();
[Test]
public void SplitCharCountTest()
{
string[] split = "123-456-789-0".Split('-', 2).ToArray();
Assert.AreEqual(2, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456-789-0", split[1]);
}
Assert.AreEqual(2, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456-789-0", split[1]);
}
[Test]
public void SplitChunksizeTest()
{
string[] split = "1234567890".Split(3).ToArray();
[Test]
public void SplitChunksizeTest()
{
string[] split = "1234567890".Split(3).ToArray();
Assert.AreEqual(4, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456", split[1]);
Assert.AreEqual("789", split[2]);
Assert.AreEqual("0", split[3]);
}
Assert.AreEqual(4, split.Length);
Assert.AreEqual("123", split[0]);
Assert.AreEqual("456", split[1]);
Assert.AreEqual("789", split[2]);
Assert.AreEqual("0", split[3]);
}
[TestCase("12345", " 12 3 4 \t 5\n")]
public void RemoveWhitespaceTest(string expected, string value)
{
Assert.AreEqual(expected, value.RemoveWhitespace());
}
[TestCase("12345", " 12 3 4 \t 5\n")]
public void RemoveWhitespaceTest(string expected, string value)
{
Assert.AreEqual(expected, value.RemoveWhitespace());
}
[Test]
public void RemoveCharactersTest()
{
Assert.AreEqual("13457890", "1234567890".Remove(new[] { '2', '6' }));
}
[TestCase("1234567890", "12345", "67890")]
[TestCase("foobarfoobar", "bar", "foofoo")]
public void RemoveStringTest(string value, string other, string expected)
{
Assert.AreEqual(expected, value.Remove(other));
}
[TestCase(true, "27652")]
[TestCase(false, "a27652")]
public void IsNumericTest(bool expected, string value)
{
Assert.AreEqual(expected, value.IsNumeric());
}
}
[TestCase("1234567890", new[] {'2', '6'}, "13457890")]
[TestCase("912529434324", new[] {'-', '(', ')', '.', '+'}, "912529434324")]
public void RemoveCharactersTest(string value, IEnumerable<char> characters, string expected)
{
Assert.AreEqual(expected, value.Remove(characters));
}
[TestCase(true, "27652")]
[TestCase(false, "a27652")]
public void IsNumericTest(bool expected, string value)
{
Assert.AreEqual(expected, value.IsNumeric());
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Extensions
{
[TestFixture]
public sealed class TimeSpanExtensionsTest
{
[Test]
public void ToReadableStringTest()
{
Assert.Inconclusive();
}
[TestCase(0, 0, 0)]
[TestCase(12, 1, 13)]
[TestCase(23, 1, 0)]
[TestCase(6, -12, 18)]
public void AddHoursAndWrapTest(int hours, int addHours, int expectedHours)
{
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap(addHours).Hours);
}
[TestCase(0, 0, 0)]
[TestCase(12, 1, 13)]
[TestCase(23, 1, 12)]
[TestCase(6, -12, 6)]
public void AddHoursAndWrap12Hour(int hours, int addHours, int expectedHours)
{
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap12Hour(addHours).Hours);
}
[TestCase(0, 0, 0)]
[TestCase(30, 1, 31)]
[TestCase(59, 1, 0)]
[TestCase(30, -60, 30)]
public void AddMinutesAndWrap(int minutes, int addMinutes, int expectedMinutes)
{
Assert.AreEqual(expectedMinutes, new TimeSpan(0, minutes, 0).AddMinutesAndWrap(addMinutes).Minutes);
}
}
}

View File

@@ -155,6 +155,22 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
}
[TestCase(typeof(int), "System.Int32")]
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")]
[TestCase(typeof(KeyValuePair<int, string>), "System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]")]
[TestCase(typeof(List<>), "System.Collections.Generic.List`1")]
public void GetMinimalNameTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetMinimalName());
}
[TestCase(typeof(int), "System.Int32, System.Private.CoreLib")]
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
{
Assert.AreEqual(expected, type.GetNameWithoutAssemblyDetails());
}
[TestCase(typeof(string), "string")]
[TestCase(typeof(int?), "int?")]
[TestCase(typeof(List<int?>), "List<int?>")]

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
@@ -49,10 +50,10 @@ namespace ICD.Common.Utils.Tests.Extensions
reader.ReadToNextElement();
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
Assert.AreEqual(2, attributes.Length);
Assert.AreEqual("attr1", attributes[0].Name);
Assert.AreEqual("attr2", attributes[1].Name);
Assert.AreEqual("attr1", attributes[0].Key);
Assert.AreEqual("attr2", attributes[1].Key);
}
[Test]

View File

@@ -1,4 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
@@ -19,9 +20,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -37,10 +37,11 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(port, new IcdUriBuilder {Port = port}.Port);
}
[TestCase("test")]
public void QueryTest(string query)
[TestCase("?test", "test")]
[TestCase("??test", "?test")]
public void QueryTest(string expected, string query)
{
Assert.AreEqual(query, new IcdUriBuilder {Query = query}.Query);
Assert.AreEqual(expected, new IcdUriBuilder {Query = query}.Query);
}
[TestCase("test")]
@@ -63,14 +64,17 @@ namespace ICD.Common.Utils.Tests
#endregion
[TestCase("http://localhost/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http://localhost:80/", null, null, null, null, (ushort)80, null, null, null)]
[TestCase("http://username@localhost/", null, null, null, null, (ushort)0, null, null, "username")]
[TestCase("http://localhost/", null, null, "password", null, (ushort)0, null, null, null)]
[TestCase("https://localhost/", null, null, null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, null, null, "test", (ushort)0, null, null, null)]
[TestCase("http://localhost/test", null, null, null, "/test", (ushort)0, null, null, null)]
[TestCase("http://localhost//test", null, null, null, "//test", (ushort)0, null, null, null)]
[TestCase("/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http:///", null, null, null, null, (ushort)0, null, "http", null)]
[TestCase("http://localhost:80/", null, "localhost", null, null, (ushort)80, null, "http", null)]
[TestCase("http://username@localhost/", null, "localhost", null, null, (ushort)0, null, "http", "username")]
[TestCase("http://localhost/", null, "localhost", "password", null, (ushort)0, null, "http", null)]
[TestCase("https://localhost/", null, "localhost", null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, "localhost", null, "test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/test", null, "localhost", null, "/test", (ushort)0, null, "http", null)]
[TestCase("http://localhost//test", null, "localhost", null, "//test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/test?a=b", null, "localhost", null, "/test", (ushort)0, "a=b", "http", null)]
[TestCase("http://localhost/test??a=b", null, "localhost", null, "/test", (ushort)0, "?a=b", "http", null)]
public void ToStringTest(string expected, string fragment, string address, string password, string path, ushort port,
string query, string scheme, string userName)
{

View File

@@ -2,7 +2,6 @@
using ICD.Common.Utils.IO;
using ICD.Common.Utils.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Json
@@ -11,25 +10,7 @@ namespace ICD.Common.Utils.Tests.Json
public sealed class JsonUtilsTest
{
[Test]
public void CacheTypeTest()
{
Assert.Inconclusive();
}
[Test]
public void ParseDateTimeTest()
{
Assert.Inconclusive();
}
[Test]
public void TryParseDateTimeTest()
{
Assert.Inconclusive();
}
[Test]
public void PrintTest()
public void FormatTest()
{
Assert.Inconclusive();
}
@@ -141,32 +122,6 @@ namespace ICD.Common.Utils.Tests.Json
Assert.AreEqual("test message", messageName);
}
[Test]
public void DeserializeTypeTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token);
Assert.AreEqual(10, value);
}
[Test]
public void DeserializeTestSerializerTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token, new JsonSerializer());
Assert.AreEqual(10, value);
}
public sealed class TestSerializable
{
private const string PROPERTY_NAME = "Test";

View File

@@ -1,14 +1,13 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Tests
{
[TestFixture, UsedImplicitly]
[TestFixture]
public sealed class MathUtilsTest
{
[Test, UsedImplicitly]
[Test]
public void ClampTest()
{
Assert.AreEqual(MathUtils.Clamp(-10, 0, 0), 0);
@@ -24,9 +23,13 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(MathUtils.Clamp(20, 10, 10), 10);
}
[Test, UsedImplicitly]
[Test]
public void MapRangeTest()
{
Assert.AreEqual(5, MathUtils.MapRange(-100, 100, 0, 10, 0));
Assert.AreEqual(7, MathUtils.MapRange(-100, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(-100, 100, 0, 10, 100));
Assert.AreEqual(0, MathUtils.MapRange(0, 100, 0, 10, 0));
Assert.AreEqual(5, MathUtils.MapRange(0, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(0, 100, 0, 10, 100));
@@ -36,7 +39,7 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(100, MathUtils.MapRange(0, 10, 0, 100, 10));
}
[Test, UsedImplicitly]
[Test]
public void GetRangesTest()
{
IEnumerable<int> values = new [] { 1, 3, 5, 6, 7, 8, 9, 10, 12 };
@@ -57,11 +60,21 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(12, ranges[3][1]);
}
[Test, UsedImplicitly]
[Test]
public void RoundToNearestTest()
{
IEnumerable<int> values = new [] { 0, 15, 30, 45 };
Assert.AreEqual(15, MathUtils.RoundToNearest(21, values));
}
[TestCase(10, 10, 0)]
[TestCase(-10, 10, 0)]
[TestCase(9, 3, 0)]
[TestCase(3, 2, 1)]
[TestCase(-3, 2, 1)]
public void ModulusTest(int value, int mod, int expected)
{
Assert.AreEqual(expected, MathUtils.Modulus(value, mod));
}
}
}

View File

@@ -127,6 +127,24 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(clique.Contains(6));
}
[Test]
public void GetCliqueSingleNodeTest()
{
int[] clique = RecursionUtils.GetClique(1, n => s_CliqueGraph[n]).ToArray();
Assert.AreEqual(4, clique.Length);
Assert.IsTrue(clique.Contains(1));
Assert.IsTrue(clique.Contains(2));
Assert.IsTrue(clique.Contains(3));
Assert.IsTrue(clique.Contains(4));
clique = RecursionUtils.GetClique(5, n => s_CliqueGraph[n]).ToArray();
Assert.AreEqual(2, clique.Length);
Assert.IsTrue(clique.Contains(5));
Assert.IsTrue(clique.Contains(6));
}
[Test]
public void BreadthFirstSearchTest()
{

View File

@@ -2,6 +2,8 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.EventArguments;
using ICD.Common.Utils.Extensions;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -149,5 +151,75 @@ namespace ICD.Common.Utils.Tests
// Everything else
Assert.AreEqual(10, ReflectionUtils.ChangeType("10", typeof(int)));
}
#region Subscription Tests
[Test]
public void SubscribeEventTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
Delegate del = ReflectionUtils.SubscribeEvent<IntEventArgs>(this, eventInfo, IncrementCount);
Assert.NotNull(del);
m_Count = 0;
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(10, m_Count);
OnIncrementCount = null;
}
[Test]
public void SubscribeEventMethodInfoTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
MethodInfo methodInfo =
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
Assert.NotNull(del);
m_Count = 0;
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(10, m_Count);
OnIncrementCount = null;
}
[Test]
public void UnsubscribeEventTest()
{
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
MethodInfo methodInfo =
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
Assert.NotNull(del);
m_Count = 0;
ReflectionUtils.UnsubscribeEvent(this, eventInfo, del);
OnIncrementCount.Raise(this, new IntEventArgs(10));
Assert.AreEqual(0, m_Count);
}
// Event has to be public
public event EventHandler<IntEventArgs> OnIncrementCount;
private int m_Count;
private void IncrementCount(object sender, IntEventArgs args)
{
m_Count += args.Data;
}
#endregion
}
}

View File

@@ -0,0 +1,38 @@
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class RegexUtilsTest
{
[Test]
public static void MatchesTest()
{
Assert.Inconclusive();
}
[Test]
public static void MatchesOptionsTest()
{
Assert.Inconclusive();
}
[TestCase(@"[assembly: AssemblyFileVersion(""1.2.3"")][assembly: AssemblyFileVersion(""1.2.3"")]",
@"[assembly: AssemblyFileVersion(""2.0.3.0"")][assembly: AssemblyFileVersion(""2.0.3.0"")]",
@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)",
"version",
"1.2.3")]
public static void ReplaceGroupTest(string expected, string input, string pattern, string groupName,
string replacement)
{
string result = RegexUtils.ReplaceGroup(input, pattern, groupName, replacement);
Assert.AreEqual(expected, result);
}
[Test]
public static void ReplaceGroupFuncTest()
{
Assert.Inconclusive();
}
}
}

View File

@@ -0,0 +1,17 @@
using ICD.Common.Utils.Timers;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Timers
{
[TestFixture]
public sealed class IcdStopwatchTest
{
[Test]
public void ConstructorTest()
{
var stopwatch = new IcdStopwatch();
ThreadingUtils.Sleep(100);
Assert.AreEqual(0, stopwatch.ElapsedMilliseconds);
}
}
}

View File

@@ -1,17 +0,0 @@
using ICD.Common.Properties;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Xml
{
[TestFixture]
public sealed class IcdXmlAttributeTest
{
[Test, UsedImplicitly]
public void ValueAsIntTest()
{
IcdXmlAttribute attribute = new IcdXmlAttribute("test", "12");
Assert.AreEqual("12", attribute.Value);
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Linq;
using ICD.Common.Utils.Xml;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests.Xml
{
[TestFixture]
public sealed class IcdXmlConvertTest
{
[Test]
public void DeserializeArrayGenericTest()
{
const string xml = @"<A>
<B>1</B>
<B>2</B>
</A>";
using (IcdXmlReader reader = new IcdXmlReader(xml))
{
// Read to the first element
reader.Read();
int[] values = IcdXmlConvert.DeserializeArray<int>(reader).ToArray();
Assert.AreEqual(new[] {1, 2}, values);
}
}
[Test]
public void DeserializeArrayTest()
{
Assert.Inconclusive();
}
}
}

View File

@@ -56,12 +56,12 @@ namespace ICD.Common.Utils.Tests.Xml
{
reader.ReadToNextElement();
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
Assert.AreEqual(2, attributes.Length);
Assert.AreEqual("attr1", attributes[0].Name);
Assert.AreEqual("attr1", attributes[0].Key);
Assert.AreEqual("1", attributes[0].Value);
Assert.AreEqual("attr2", attributes[1].Name);
Assert.AreEqual("attr2", attributes[1].Key);
Assert.AreEqual("2", attributes[1].Value);
}
}

View File

@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -20,175 +17,6 @@ namespace ICD.Common.Utils
/// </summary>
public static class AttributeUtils
{
// Avoid caching the same assembly multiple times.
private static readonly IcdHashSet<Assembly> s_CachedAssemblies;
private static readonly IcdHashSet<Type> s_CachedTypes;
private static readonly Dictionary<Attribute, MethodInfo> s_AttributeToMethodCache;
private static readonly Dictionary<Attribute, Type> s_AttributeToTypeCache;
private static readonly Dictionary<Type, IcdHashSet<Attribute>> s_TypeToAttributesCache;
private static ILoggerService Logger { get { return ServiceProvider.TryGetService<ILoggerService>(); } }
/// <summary>
/// Constructor.
/// </summary>
static AttributeUtils()
{
s_CachedAssemblies = new IcdHashSet<Assembly>();
s_CachedTypes = new IcdHashSet<Type>();
s_AttributeToMethodCache = new Dictionary<Attribute, MethodInfo>();
s_AttributeToTypeCache = new Dictionary<Attribute, Type>();
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
}
#region Caching
/// <summary>
/// Pre-emptively caches the given assemblies for lookup.
/// </summary>
/// <param name="assemblies"></param>
public static void CacheAssemblies(IEnumerable<Assembly> assemblies)
{
if (assemblies == null)
throw new ArgumentNullException("assemblies");
foreach (Assembly assembly in assemblies)
CacheAssembly(assembly);
}
/// <summary>
/// Pre-emptively caches the given assembly for lookup.
/// </summary>
/// <param name="assembly"></param>
public static bool CacheAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
if (s_CachedAssemblies.Contains(assembly))
return true;
#if SIMPLSHARP
CType[] types;
#else
Type[] types;
#endif
try
{
types = assembly.GetTypes();
}
#if STANDARD
catch (ReflectionTypeLoadException e)
{
foreach (Exception inner in e.LoaderExceptions)
{
if (inner is System.IO.FileNotFoundException)
{
Logger.AddEntry(eSeverity.Error,
"{0} failed to cache assembly {1} - Could not find one or more dependencies by path",
typeof(AttributeUtils).Name, assembly.GetName().Name);
continue;
}
Logger.AddEntry(eSeverity.Error, inner, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
assembly.GetName().Name);
}
return false;
}
#endif
catch (TypeLoadException e)
{
#if SIMPLSHARP
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
assembly.GetName().Name);
#else
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1} - could not load type {2}",
typeof(AttributeUtils).Name, assembly.GetName().Name, e.TypeName);
#endif
return false;
}
foreach (var type in types)
CacheType(type);
s_CachedAssemblies.Add(assembly);
return true;
}
/// <summary>
/// Pre-emptively caches the given type for lookup.
/// </summary>
/// <param name="type"></param>
#if SIMPLSHARP
public static void CacheType(CType type)
#else
public static void CacheType(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
if (s_CachedTypes.Contains(type))
return;
s_CachedTypes.Add(type);
MethodInfo[] methods;
try
{
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
foreach (Attribute attribute in s_TypeToAttributesCache[type])
s_AttributeToTypeCache[attribute] = type;
methods = type.GetMethods();
}
// GetMethods for Open Generic Types is not supported.
catch (NotSupportedException)
{
return;
}
// Not sure why this happens :/
catch (InvalidProgramException)
{
return;
}
foreach (MethodInfo method in methods)
CacheMethod(method);
}
/// <summary>
/// Caches the method.
/// </summary>
/// <param name="method"></param>
private static void CacheMethod(MethodInfo method)
{
if (method == null)
throw new ArgumentNullException("method");
foreach (Attribute attribute in ReflectionExtensions.GetCustomAttributes<Attribute>(method, false))
s_AttributeToMethodCache[attribute] = method;
}
#endregion
#region Lookup
/// <summary>
/// Gets the class attributes of the given generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>()
where T : Attribute
{
return s_AttributeToTypeCache.Select(kvp => kvp.Key)
.OfType<T>();
}
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
@@ -197,12 +25,24 @@ namespace ICD.Common.Utils
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type)
where T : Attribute
{
return GetClassAttribute<T>(type, false);
}
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <param name="inherit"></param>
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type, bool inherit)
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes<T>(type).FirstOrDefault();
return GetClassAttributes<T>(type, inherit).FirstOrDefault();
}
/// <summary>
@@ -212,72 +52,56 @@ namespace ICD.Common.Utils
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes(type).OfType<T>();
return GetClassAttributes<T>(type, false);
}
/// <summary>
/// Gets the attributes on the given class.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Attribute> GetClassAttributes(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
CacheType(type);
IcdHashSet<Attribute> attributes;
return s_TypeToAttributesCache.TryGetValue(type, out attributes)
? attributes.ToArray(attributes.Count)
: Enumerable.Empty<Attribute>();
}
/// <summary>
/// Gets the type with the given attribute.
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static Type GetClass(Attribute attribute)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
return s_AttributeToTypeCache[attribute];
}
/// <summary>
/// Gets all of the cached method attributes of the given type.
/// Gets the attributes on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <param name="inherit"></param>
/// <returns></returns>
public static IEnumerable<T> GetMethodAttributes<T>()
where T : Attribute
public static IEnumerable<T> GetClassAttributes<T>(Type type, bool inherit)
{
return s_AttributeToMethodCache.Select(p => p.Key)
.OfType<T>()
.ToArray();
if (type == null)
throw new ArgumentNullException("type");
// ReSharper disable InvokeAsExtensionMethod
return ReflectionExtensions.GetCustomAttributes<T>(
#if SIMPLSHARP
(CType)
#endif
type, inherit);
// ReSharper restore InvokeAsExtensionMethod
}
/// <summary>
/// Gets the cached method for the given attribute.
/// Returns the properties on the given instance with property attributes of the given type.
/// </summary>
/// <param name="attribute"></param>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="inherit"></param>
/// <returns></returns>
public static MethodInfo GetMethod(Attribute attribute)
public static IEnumerable<PropertyInfo> GetProperties<T>(object instance, bool inherit)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
if (instance == null)
throw new ArgumentNullException("instance");
return s_AttributeToMethodCache[attribute];
return instance.GetType()
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetProperties()
// ReSharper disable InvokeAsExtensionMethod
.Where(p => ReflectionExtensions.GetCustomAttributes<T>(p, inherit).Any());
// ReSharper restore InvokeAsExtensionMethod
}
#endregion
}
}

View File

@@ -5,7 +5,7 @@ namespace ICD.Common.Utils.Attributes
/// <summary>
/// AbstractIcdAttribute is the base class for all ICD attributes.
/// </summary>
public abstract class AbstractIcdAttribute : Attribute
public abstract class AbstractIcdAttribute : Attribute, IIcdAttribute
{
}
}

View File

@@ -0,0 +1,6 @@
namespace ICD.Common.Utils.Attributes
{
public interface IIcdAttribute
{
}
}

View File

@@ -0,0 +1,520 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Attributes
{
/// <summary>
/// Indicates the valid ranges for a given value if that range is not equal to the range of the data type.
/// </summary>
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Parameter |
AttributeTargets.ReturnValue)]
public sealed class RangeAttribute : AbstractIcdAttribute
{
/// <summary>
/// Remaps from the source numeric min/max to double min/max.
/// </summary>
private static readonly Dictionary<Type, Func<double, double>> s_Clamp =
new Dictionary<Type, Func<double, double>>
{
// Duh
{typeof(double), o => o},
// Signed
{typeof(short), o => o < short.MinValue ? short.MinValue : o > short.MaxValue ? short.MaxValue : o},
{typeof(int), o => o < int.MinValue ? int.MinValue : o > int.MaxValue ? int.MaxValue : o},
{typeof(long), o => o < long.MinValue ? long.MinValue : o > long.MaxValue ? long.MaxValue : o},
{typeof(float),o => o < float.MinValue ? float.MinValue : o > float.MaxValue ? float.MaxValue : o},
{typeof(decimal), o => o < (double)decimal.MinValue ? (double)decimal.MinValue : o > (double)decimal.MaxValue ? (double)decimal.MaxValue : o},
// Unsigned
{typeof(ushort), o => o < ushort.MinValue ? ushort.MinValue : o > ushort.MaxValue ? ushort.MaxValue : o},
{typeof(uint), o => o < uint.MinValue ? uint.MinValue : o > uint.MaxValue ? uint.MaxValue : o},
{typeof(ulong), o => o < ulong.MinValue ? ulong.MinValue : o > ulong.MaxValue ? ulong.MaxValue : o},
{typeof(byte), o => o < byte.MinValue ? byte.MinValue : o > byte.MaxValue ? byte.MaxValue : o}
};
/// <summary>
/// Remaps from the source numeric min/max to double min/max.
/// </summary>
private static readonly Dictionary<Type, Func<object, double>> s_RemapToDouble =
new Dictionary<Type, Func<object, double>>
{
// Duh
{ typeof(double), o => (double)o},
// Signed - Clamping prevents an overflow due to loss of precision
{ typeof(short), o => MathUtils.Clamp(Convert.ToDouble(o) / short.MaxValue, -1, 1) * double.MaxValue},
{ typeof(int), o => MathUtils.Clamp(Convert.ToDouble(o) / int.MaxValue, -1, 1) * double.MaxValue},
{ typeof(long), o => MathUtils.Clamp(Convert.ToDouble(o) / long.MaxValue, -1, 1) * double.MaxValue},
{ typeof(float), o => MathUtils.Clamp(Convert.ToDouble(o) / float.MaxValue, -1, 1) * double.MaxValue},
{ typeof(decimal), o => MathUtils.Clamp(Convert.ToDouble(o) / (double)decimal.MaxValue, -1, 1) * double.MaxValue},
// Unsigned
{ typeof(ushort), o => MathUtils.Clamp((Convert.ToDouble(o) / ushort.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(uint), o => MathUtils.Clamp((Convert.ToDouble(o) / uint.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(ulong), o => MathUtils.Clamp((Convert.ToDouble(o) / ulong.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
{ typeof(byte), o => MathUtils.Clamp((Convert.ToDouble(o) / byte.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue}
};
/// <summary>
/// Remaps from the double min/max to target numeric min/max.
/// </summary>
private static readonly Dictionary<Type, Func<double, object>> s_RemapFromDouble =
new Dictionary<Type, Func<double, object>>
{
// Duh
{typeof(double), v => v},
// Signed
{typeof(short), v => (short)(v / double.MaxValue * short.MaxValue)},
{typeof(int), v => (int)(v / double.MaxValue * int.MaxValue)},
{typeof(long), v => (long)(v / double.MaxValue * long.MaxValue)},
{typeof(float), v => (float)(v / double.MaxValue * float.MaxValue)},
{typeof(decimal), v => (decimal)(v / double.MaxValue) * decimal.MaxValue},
// Unsigned
{typeof(ushort), v => (ushort)((v / double.MaxValue + 1) / 2 * ushort.MaxValue)},
{typeof(uint), v => (uint)((v / double.MaxValue + 1) / 2 * uint.MaxValue)},
{typeof(ulong), v => (ulong)((v / double.MaxValue + 1) / 2 * ulong.MaxValue)},
{typeof(byte), v => (byte)((v / double.MaxValue + 1) / 2 * byte.MaxValue)}
};
/// <summary>
/// Gets the min value of a given numeric type as a double.
/// </summary>
private static readonly Dictionary<Type, double> s_MinAsDouble =
new Dictionary<Type, double>
{
// Duh
{typeof(double), double.MinValue},
// Signed
{typeof(short), Convert.ToDouble(short.MinValue)},
{typeof(int), Convert.ToDouble(int.MinValue)},
{typeof(long), Convert.ToDouble(long.MinValue)},
{typeof(float), Convert.ToDouble(float.MinValue)},
{typeof(decimal), Convert.ToDouble(decimal.MinValue)},
// Unsigned
{typeof(ushort), Convert.ToDouble(ushort.MinValue)},
{typeof(uint), Convert.ToDouble(uint.MinValue)},
{typeof(ulong), Convert.ToDouble(ulong.MinValue)},
{typeof(byte), Convert.ToDouble(byte.MinValue)}
};
/// <summary>
/// Gets the min value of a given numeric type as a double.
/// </summary>
private static readonly Dictionary<Type, double> s_MaxAsDouble =
new Dictionary<Type, double>
{
// Duh
{typeof(double), double.MaxValue},
// Signed
{typeof(short), Convert.ToDouble(short.MaxValue)},
{typeof(int), Convert.ToDouble(int.MaxValue)},
{typeof(long), Convert.ToDouble(long.MaxValue)},
{typeof(float), Convert.ToDouble(float.MaxValue)},
{typeof(decimal), Convert.ToDouble(decimal.MaxValue)},
// Unsigned
{typeof(ushort), Convert.ToDouble(ushort.MaxValue)},
{typeof(uint), Convert.ToDouble(uint.MaxValue)},
{typeof(ulong), Convert.ToDouble(ulong.MaxValue)},
{typeof(byte), Convert.ToDouble(byte.MaxValue)}
};
private readonly object m_Min;
private readonly object m_Max;
#region Properties
/// <summary>
/// Gets the min value for this range.
/// </summary>
public object Min { get { return m_Min; } }
/// <summary>
/// Gets the max value for this range.
/// </summary>
public object Max { get { return m_Max; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(ushort min, ushort max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(short min, short max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(uint min, uint max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(int min, int max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(ulong min, ulong max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(long min, long max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(float min, float max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(double min, double max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(byte min, byte max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(sbyte min, sbyte max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(decimal min, decimal max)
: this((object)min, (object)max)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(object min, object max)
{
if (min == null)
throw new ArgumentNullException("min");
if (max == null)
throw new ArgumentNullException("max");
if (min.GetType() != max.GetType())
throw new ArgumentException("Min and Max types do not match");
if (!min.GetType().IsNumeric())
throw new ArgumentException("Given types are not numeric");
m_Min = min;
m_Max = max;
}
#endregion
#region Methods
/// <summary>
/// Remaps the given numeric value from its min/max range into double min/max range.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static double RemapToDouble(object value)
{
if (value == null)
throw new ArgumentNullException("value");
Func<object, double> remap;
if (!s_RemapToDouble.TryGetValue(value.GetType(), out remap))
throw new NotSupportedException("Value type is not supported.");
return remap(value);
}
/// <summary>
/// Remaps the given double value from its min/max range into the target type min/max range.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object RemapFromDouble(double value, Type type)
{
if (type == null)
throw new ArgumentNullException("type");
Func<double, object> remap;
if (!s_RemapFromDouble.TryGetValue(type, out remap))
throw new NotSupportedException("Value type is not supported.");
return remap(value);
}
/// <summary>
/// Clamps the given numeric value into the valid ranges of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Clamp(object value, Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double doubleValue = Convert.ToDouble(value);
double clamped = Clamp(doubleValue, type);
return Convert.ChangeType(clamped, value.GetType(), CultureInfo.InvariantCulture);
}
/// <summary>
/// Clamps the given double value into the valid ranges of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static double Clamp(double value, Type type)
{
if (type == null)
throw new ArgumentNullException("type");
Func<double, double> clamp;
if (!s_Clamp.TryGetValue(type, out clamp))
throw new NotSupportedException("Value type is not supported.");
return clamp(value);
}
/// <summary>
/// Remaps the numeric value into the min-max range of the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object Remap(object value, Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double intermediate = RemapToDouble(value);
return RemapFromDouble(intermediate, type);
}
/// <summary>
/// Clamps the given numeric value to the defined min/max then remaps to the target numeric type.
/// </summary>
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public object ClampMinMaxThenRemap(object value, Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double min = Convert.ToDouble(Min);
double max = Convert.ToDouble(Max);
double doubleValue = Convert.ToDouble(value);
double clamped = MathUtils.Clamp(doubleValue, min, max);
object remapped = RemapMinMax(clamped, type);
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
}
/// <summary>
/// Remaps the given numeric value to the defined min/max.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public object RemapMinMax(object value)
{
if (value == null)
throw new ArgumentNullException("value");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double sourceMin = GetMinAsDouble(value.GetType());
double sourceMax = GetMaxAsDouble(value.GetType());
double targetMin = Convert.ToDouble(Min);
double targetMax = Convert.ToDouble(Max);
double doubleValue = Convert.ToDouble(value);
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
}
private object RemapMinMax(object value, Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
double sourceMin = Convert.ToDouble(Min);
double sourceMax = Convert.ToDouble(Max);
double targetMin = GetMinAsDouble(type);
double targetMax = GetMaxAsDouble(type);
double doubleValue = Convert.ToDouble(value);
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
return Convert.ChangeType(remapped, type, CultureInfo.InvariantCulture);
}
#endregion
#region Private Methods
/// <summary>
/// Gets the min value for the given numeric type as a double.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static double GetMinAsDouble(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
double min;
if (!s_MinAsDouble.TryGetValue(type, out min))
throw new NotSupportedException("Type is not supported.");
return min;
}
/// <summary>
/// Gets the max value for the given numeric type as a double.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static double GetMaxAsDouble(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
double max;
if (!s_MaxAsDouble.TryGetValue(type, out max))
throw new NotSupportedException("Type is not supported.");
return max;
}
#endregion
}
}

View File

@@ -1,135 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Utils.EventArguments;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// Provides a buffer for storing items to be raised in order in a new thread.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class AsyncEventQueue<T> : IEnumerable<T>, ICollection, IDisposable
{
/// <summary>
/// Raised to handle to the next item in the queue.
/// </summary>
public event EventHandler<GenericEventArgs<T>> OnItemDequeued;
private readonly Queue<T> m_Queue;
private readonly SafeCriticalSection m_QueueSection;
private readonly SafeCriticalSection m_ProcessSection;
#region Properties
public int Count { get { return m_QueueSection.Execute(() => m_Queue.Count); } }
bool ICollection.IsSynchronized { get { return true; } }
object ICollection.SyncRoot { get { return this; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
public AsyncEventQueue()
{
m_Queue = new Queue<T>();
m_QueueSection = new SafeCriticalSection();
m_ProcessSection = new SafeCriticalSection();
}
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
OnItemDequeued = null;
Clear();
}
/// <summary>
/// Enqueues the given item and begins processing the queue.
/// </summary>
/// <param name="item"></param>
public void Enqueue(T item)
{
m_QueueSection.Execute(() => m_Queue.Enqueue(item));
ThreadingUtils.SafeInvoke(ProcessQueue);
}
/// <summary>
/// Clears the queued items.
/// </summary>
public void Clear()
{
m_QueueSection.Execute(() => m_Queue.Clear());
}
#endregion
#region Private Methods
/// <summary>
/// Dequeues and raises each item in sequence.
/// </summary>
private void ProcessQueue()
{
if (!m_ProcessSection.TryEnter())
return;
try
{
T item;
while (m_Queue.Dequeue(out item))
OnItemDequeued.Raise(this, new GenericEventArgs<T>(item));
}
finally
{
m_ProcessSection.Leave();
}
}
#endregion
#region IEnumerable/ICollection
public IEnumerator<T> GetEnumerator()
{
return m_QueueSection.Execute(() => m_Queue.ToList(m_Queue.Count).GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
{
m_QueueSection.Enter();
try
{
foreach (T item in this)
{
array.SetValue(item, index);
index++;
}
}
finally
{
m_QueueSection.Leave();
}
}
#endregion
}
}

View File

@@ -30,9 +30,24 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
public BiDictionary()
: this(null)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="dict"></param>
public BiDictionary(Dictionary<TKey, TValue> dict)
{
m_KeyToValue = new Dictionary<TKey, TValue>();
m_ValueToKey = new Dictionary<TValue, TKey>();
if (dict == null)
return;
foreach (KeyValuePair<TKey, TValue> kvp in dict)
Add(kvp.Key, kvp.Value);
}
#region Methods

View File

@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Collections
{
@@ -95,7 +96,7 @@ namespace ICD.Common.Utils.Collections
if (set == null)
throw new ArgumentNullException("set");
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
IcdHashSet<T> unionSet = new IcdHashSet<T>(m_Dict.Comparer, this);
unionSet.AddRange(set);
return unionSet;
@@ -112,7 +113,7 @@ namespace ICD.Common.Utils.Collections
if (set == null)
throw new ArgumentNullException("set");
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
IcdHashSet<T> subtractSet = new IcdHashSet<T>(m_Dict.Comparer, this);
foreach (T item in set)
subtractSet.Remove(item);
@@ -131,7 +132,7 @@ namespace ICD.Common.Utils.Collections
if (set == null)
throw new ArgumentNullException("set");
IcdHashSet<T> intersectionSet = new IcdHashSet<T>();
IcdHashSet<T> intersectionSet = new IcdHashSet<T>(m_Dict.Comparer);
foreach (T item in set.Where(Contains))
intersectionSet.Add(item);
@@ -150,7 +151,7 @@ namespace ICD.Common.Utils.Collections
if (set == null)
throw new ArgumentNullException("set");
IcdHashSet<T> output = new IcdHashSet<T>(this);
IcdHashSet<T> output = new IcdHashSet<T>(m_Dict.Comparer, this);
foreach (T item in set)
{
@@ -228,7 +229,7 @@ namespace ICD.Common.Utils.Collections
public bool SetEquals(IcdHashSet<T> set)
{
if (set == null)
return Count == 0;
throw new ArgumentNullException("set");
return Count == set.Count && set.All(Contains);
}
@@ -328,6 +329,18 @@ namespace ICD.Common.Utils.Collections
return m_Dict.Remove(item);
}
/// <summary>
/// Removes each of the items in the sequence from the collection.
/// </summary>
/// <param name="items"></param>
public void RemoveRange(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
m_Dict.RemoveAll(items);
}
#endregion
#region IEnumerable<T>

View File

@@ -32,13 +32,8 @@ namespace ICD.Common.Utils.Collections
if (key == null)
throw new ArgumentNullException("key");
if (!ContainsKey(key))
{
int index = m_OrderedKeys.AddSorted(key, m_Comparer);
m_ValuesOrderedByKey.Insert(index, value);
}
m_Dictionary[key] = value;
Remove(key);
Add(key, value);
}
}
@@ -109,9 +104,12 @@ namespace ICD.Common.Utils.Collections
throw new ArgumentNullException("key");
if (m_Dictionary.ContainsKey(key))
throw new ArgumentException("An item with the same key has already been added.", "key");
throw new ArgumentOutOfRangeException("key", "An item with the same key has already been added.");
this[key] = value;
int index = m_OrderedKeys.AddSorted(key, m_Comparer);
m_ValuesOrderedByKey.Insert(index, value);
m_Dictionary[key] = value;
}
public void Clear()

View File

@@ -77,7 +77,7 @@ namespace ICD.Common.Utils.Collections
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
{
queue = new List<T>();
m_PriorityToQueue[priority] = queue;
m_PriorityToQueue.Add(priority, queue);
}
queue.Add(item);
@@ -97,7 +97,7 @@ namespace ICD.Common.Utils.Collections
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
{
queue = new List<T>();
m_PriorityToQueue[priority] = queue;
m_PriorityToQueue.Add(priority, queue);
}
queue.Insert(0, item);
@@ -136,7 +136,7 @@ namespace ICD.Common.Utils.Collections
bool inserted = false;
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue)
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue.ToArray())
{
int[] removeIndices =
kvp.Value
@@ -166,6 +166,9 @@ namespace ICD.Common.Utils.Collections
inserted = true;
}
if (kvp.Value.Count == 0)
m_PriorityToQueue.Remove(kvp.Key);
}
if (!inserted)
@@ -194,24 +197,30 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public bool TryDequeue(out T output)
{
output = default(T);
while (true)
{
output = default(T);
KeyValuePair<int, List<T>> kvp;
if (!m_PriorityToQueue.TryFirst(out kvp))
return false;
KeyValuePair<int, List<T>> kvp;
if (!m_PriorityToQueue.TryFirst(out kvp))
return false;
int priority = kvp.Key;
List<T> queue = kvp.Value;
int priority = kvp.Key;
List<T> queue = kvp.Value;
output = queue[0];
queue.RemoveAt(0);
bool found = queue.TryFirst(out output);
if (found)
{
queue.RemoveAt(0);
m_Count--;
}
if (queue.Count == 0)
m_PriorityToQueue.Remove(priority);
if (queue.Count == 0)
m_PriorityToQueue.Remove(priority);
m_Count--;
return true;
if (found)
return true;
}
}
/// <summary>
@@ -233,10 +242,7 @@ namespace ICD.Common.Utils.Collections
public void CopyTo(Array array, int index)
{
foreach (T item in this)
{
array.SetValue(item, index);
index++;
}
array.SetValue(item, index++);
}
#endregion

View File

@@ -56,7 +56,16 @@ namespace ICD.Common.Utils.Collections
{
OnItemDequeued = null;
m_DequeueTimer.Dispose();
m_QueueSection.Enter();
try
{
m_DequeueTimer.Dispose();
}
finally
{
m_QueueSection.Leave();
}
}
/// <summary>

View File

@@ -2,7 +2,6 @@
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Collections
{
@@ -16,8 +15,6 @@ namespace ICD.Common.Utils.Collections
private readonly LinkedList<TContents> m_Collection;
private int m_MaxSize;
private readonly SafeCriticalSection m_CollectionLock;
#region Properties
/// <summary>
@@ -41,13 +38,13 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
public int Count { get { return m_CollectionLock.Execute(() => m_Collection.Count); } }
public int Count { get { return m_Collection.Count; } }
/// <summary>
/// The IsSynchronized Boolean property returns True if the
/// collection is designed to be thread safe; otherwise, it returns False.
/// </summary>
public bool IsSynchronized { get { return true; } }
public bool IsSynchronized { get { return false; } }
/// <summary>
/// The SyncRoot property returns an object, which is used for synchronizing
@@ -64,7 +61,6 @@ namespace ICD.Common.Utils.Collections
/// <param name="maxSize"></param>
public ScrollQueue(int maxSize)
{
m_CollectionLock = new SafeCriticalSection();
m_Collection = new LinkedList<TContents>();
MaxSize = maxSize;
}
@@ -76,7 +72,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
public void Clear()
{
m_CollectionLock.Execute(() => m_Collection.Clear());
m_Collection.Clear();
}
/// <summary>
@@ -86,17 +82,8 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public void Enqueue(TContents item)
{
m_CollectionLock.Enter();
try
{
m_Collection.AddLast(item);
Trim();
}
finally
{
m_CollectionLock.Leave();
}
m_Collection.AddLast(item);
Trim();
}
/// <summary>
@@ -106,18 +93,9 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public TContents Dequeue()
{
m_CollectionLock.Enter();
try
{
TContents output = m_Collection.First.Value;
m_Collection.RemoveFirst();
return output;
}
finally
{
m_CollectionLock.Leave();
}
TContents output = Peek();
m_Collection.RemoveFirst();
return output;
}
/// <summary>
@@ -127,7 +105,7 @@ namespace ICD.Common.Utils.Collections
[PublicAPI]
public TContents Peek()
{
return m_CollectionLock.Execute(() => m_Collection.First.Value);
return m_Collection.First.Value;
}
#endregion
@@ -141,24 +119,15 @@ namespace ICD.Common.Utils.Collections
public IEnumerator<TContents> GetEnumerator()
{
return m_CollectionLock.Execute(() => m_Collection.ToList(Count).GetEnumerator());
return m_Collection.GetEnumerator();
}
void ICollection.CopyTo(Array myArr, int index)
{
m_CollectionLock.Enter();
try
foreach (TContents item in m_Collection)
{
foreach (TContents item in m_Collection)
{
myArr.SetValue(item, index);
index++;
}
}
finally
{
m_CollectionLock.Leave();
myArr.SetValue(item, index);
index++;
}
}
@@ -171,17 +140,8 @@ namespace ICD.Common.Utils.Collections
/// </summary>
private void Trim()
{
m_CollectionLock.Enter();
try
{
while (Count > MaxSize)
m_Collection.RemoveFirst();
}
finally
{
m_CollectionLock.Leave();
}
while (Count > MaxSize)
m_Collection.RemoveFirst();
}
#endregion

View File

@@ -28,6 +28,9 @@ namespace ICD.Common.Utils
public static string FormatAnsi(this eConsoleColor extends, string data)
{
// % needs to be escaped or weird things happen
data = string.IsNullOrEmpty(data) ? data : data.Replace("%", "%%");
return string.Format("{0}{1}{2}", extends.ToAnsiPrefix(), data, CONSOLE_RESET);
}

View File

@@ -79,6 +79,8 @@ namespace ICD.Common.Utils.Csv
[PublicAPI]
public void AppendValue(string value)
{
value = value ?? string.Empty;
if (!m_NewLine)
m_Writer.WrappedTextWriter.Write(m_Seperator);

Binary file not shown.

View File

@@ -0,0 +1,15 @@
namespace ICD.Common.Utils
{
public static class DateTimeUtils
{
/// <summary>
/// Converts the hour in 24 hour format to 12 hour format (1 through 12).
/// </summary>
/// <param name="hour"></param>
/// <returns></returns>
public static int To12Hour(int hour)
{
return MathUtils.Modulus(hour + 11, 12) + 1;
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Text.RegularExpressions;
namespace ICD.Common.Utils.Email
{
public static class EmailValidation
{
private const string EMAIL_REGEX = @"(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])";
public static bool IsValidEmailAddress(string emailAddress)
{
return emailAddress != null && Regex.IsMatch(emailAddress, EMAIL_REGEX);
}
}
}

View File

@@ -40,7 +40,7 @@ namespace ICD.Common.Utils
/// Returns true if the given type is an enum.
/// </summary>
/// <returns></returns>
private static bool IsEnumType(Type type)
public static bool IsEnumType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
@@ -148,7 +148,7 @@ namespace ICD.Common.Utils
/// Gets the values from an enumeration without performing any caching. This is slow because of reflection.
/// </summary>
/// <returns></returns>
public static IEnumerable<int> GetValues(Type type)
private static IEnumerable<int> GetValues(Type type)
{
if (type == null)
throw new ArgumentNullException("type");

View File

@@ -6,7 +6,17 @@
/// Constructor.
/// </summary>
/// <param name="data"></param>
public BoolEventArgs(bool data) : base(data)
public BoolEventArgs(bool data)
: base(data)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eventArgs"></param>
public BoolEventArgs(BoolEventArgs eventArgs)
: this(eventArgs.Data)
{
}
}

View File

@@ -9,5 +9,14 @@
public StringEventArgs(string data) : base(data)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eventArgs"></param>
public StringEventArgs(StringEventArgs eventArgs)
: base(eventArgs.Data)
{
}
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Globalization;
namespace ICD.Common.Utils.Extensions
{
public static class CultureInfoExtensions
{
/// <summary>
/// Returns true if the given culture uses a 24 hour time format.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool Uses24HourFormat(this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.DateTimeFormat.ShortTimePattern.Contains("H");
}
/// <summary>
/// Updates the time patterns for the given culture to use 12 hour time.
/// </summary>
/// <param name="extends"></param>
public static void ConvertTo12HourCulture(this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.IsReadOnly)
throw new InvalidOperationException("Culture is readonly");
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
dateTimeFormat.FullDateTimePattern = To12HourPattern(dateTimeFormat.FullDateTimePattern);
dateTimeFormat.LongTimePattern = To12HourPattern(dateTimeFormat.LongTimePattern);
dateTimeFormat.ShortTimePattern = To12HourPattern(dateTimeFormat.ShortTimePattern);
}
/// <summary>
/// Updates the time patterns for the given culture to use 24 hour time.
/// </summary>
/// <param name="extends"></param>
public static void ConvertTo24HourCulture(this CultureInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.IsReadOnly)
throw new InvalidOperationException("Culture is readonly");
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
dateTimeFormat.FullDateTimePattern = To24HourPattern(dateTimeFormat.FullDateTimePattern);
dateTimeFormat.LongTimePattern = To24HourPattern(dateTimeFormat.LongTimePattern);
dateTimeFormat.ShortTimePattern = To24HourPattern(dateTimeFormat.ShortTimePattern);
}
/// <summary>
/// Converts the given format pattern to use 24 hour time.
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static string To24HourPattern(string pattern)
{
if (pattern == null)
return null;
pattern = pattern.Replace(" tt", "");
return pattern.Replace("h", "H");
}
/// <summary>
/// Converts the given format pattern to use 12 hour time.
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static string To12HourPattern(string pattern)
{
if (pattern == null)
return null;
if (!pattern.Contains("t"))
pattern = pattern + " tt";
return pattern.Replace("H", "h");
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -63,5 +64,33 @@ namespace ICD.Common.Utils.Extensions
bool success = times.OrderByDescending(dt => dt).TryFirst(dt => inclusive ? target >= dt : target > dt, out latestTime);
return success ? latestTime : (DateTime?) null;
}
/// <summary>
/// Returns the DateTime representing the very start of the current day.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime StartOfDay(this DateTime extends)
{
return new DateTime(extends.Year, extends.Month, extends.Day, 0, 0, 0);
}
/// <summary>
/// Returns the DateTime representing the very end of the current day.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime EndOfDay(this DateTime extends)
{
return extends.StartOfDay() + new TimeSpan(24, 0, 0);
}
[PublicAPI]
public static double ToUnixTimestamp(this DateTime extends)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = extends.ToUniversalTime() - origin;
return Math.Floor(diff.TotalSeconds);
}
}
}

View File

@@ -19,6 +19,9 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
if (keys == null)
throw new ArgumentNullException("keys");
foreach (TKey key in keys)
extends.Remove(key);
}
@@ -66,6 +69,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="key"></param>
/// <returns></returns>
[CanBeNull]
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
{
@@ -122,8 +126,63 @@ namespace ICD.Common.Utils.Extensions
if (key == null)
throw new ArgumentNullException("key");
extends[key] = extends.GetDefault(key, defaultValue);
return extends[key];
TValue value = extends.GetDefault(key, defaultValue);
extends[key] = value;
return value;
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise add a new value to the dictionary and return it.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
where TValue : new()
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return extends.GetOrAddNew(key, () => ReflectionUtils.CreateInstance<TValue>());
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise add a new value to the dictionary and return it.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="valueFunc"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key, Func<TValue> valueFunc)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
TValue value;
if (!extends.TryGetValue(key, out value))
{
value = valueFunc();
extends.Add(key, value);
}
return value;
}
/// <summary>

View File

@@ -58,7 +58,18 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
return extends.TryFirst(i => true, out item);
IList<T> list = extends as IList<T>;
if (list == null)
return extends.TryFirst(i => true, out item);
item = default(T);
if (list.Count <= 0)
return false;
item = list[0];
return true;
}
/// <summary>
@@ -106,7 +117,18 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
return extends.TryLast(i => true, out item);
IList<T> list = extends as IList<T>;
if (list == null)
return extends.TryLast(i => true, out item);
item = default(T);
if (list.Count <= 0)
return false;
item = list[list.Count - 1];
return true;
}
/// <summary>
@@ -156,17 +178,32 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
if (index < 0)
throw new ArgumentOutOfRangeException("index");
item = default(T);
try
IList<T> list = extends as IList<T>;
if (list != null)
{
item = extends.ElementAt(index);
if (index >= list.Count)
return false;
item = list[index];
return true;
}
catch (ArgumentOutOfRangeException)
int current = 0;
foreach (T value in extends)
{
return false;
if (current == index)
{
item = value;
return true;
}
current++;
}
return false;
}
/// <summary>
@@ -227,6 +264,12 @@ namespace ICD.Common.Utils.Extensions
if (comparer == null)
throw new ArgumentNullException("comparer");
// Simple count check
ICollection<T> a = extends as ICollection<T>;
ICollection<T> b = other as ICollection<T>;
if (a != null && b != null && a.Count != b.Count)
return false;
using (IEnumerator<T> firstPos = extends.GetEnumerator())
{
using (IEnumerator<T> secondPos = other.GetEnumerator())
@@ -285,6 +328,12 @@ namespace ICD.Common.Utils.Extensions
if (comparer == null)
throw new ArgumentNullException("comparer");
// Simple count check
ICollection<T> a = extends as ICollection<T>;
ICollection<T> b = other as ICollection<T>;
if (a != null && b != null && a.Count != b.Count)
return false;
Dictionary<T, int> count = new Dictionary<T, int>(comparer);
foreach (T item in extends)
@@ -383,7 +432,11 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
extends.ForEach(item => { });
// ReSharper disable UnusedVariable
foreach (T item in extends)
// ReSharper restore UnusedVariable
{
}
}
/// <summary>
@@ -616,7 +669,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> extends, IComparer<T> comparer)
public static IOrderedEnumerable<T> Order<T>(this IEnumerable<T> extends, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -634,7 +687,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> extends, IComparer<T> comparer)
public static IOrderedEnumerable<T> OrderDescending<T>(this IEnumerable<T> extends, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -692,8 +745,22 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
ICollection<T> collection = extends as ICollection<T> ?? extends.ToArray();
collection.CopyTo(array, index);
if (array == null)
throw new ArgumentNullException("array");
ICollection<T> collection = extends as ICollection<T>;
if (collection != null)
{
collection.CopyTo(array, index);
return;
}
int current = 0;
foreach (T item in extends)
{
array[index + current] = item;
current++;
}
}
/// <summary>
@@ -707,7 +774,7 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
return new IcdHashSet<T>(extends);
return extends.ToIcdHashSet(EqualityComparer<T>.Default);
}
/// <summary>
@@ -778,7 +845,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> extends)
public static Dictionary<int, T> ToIndexedDictionary<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -795,7 +862,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<uint, T> ToDictionaryUInt<T>(this IEnumerable<T> extends)
public static Dictionary<uint, T> ToIndexedDictionaryUInt<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -1,374 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with JSON.
/// </summary>
public static class JsonExtensions
{
/// <summary>
/// Writes the object value.
/// </summary>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
/// <param name="converter"></param>
[PublicAPI]
public static void WriteObject(this JsonWriter extends, object value, JsonSerializer serializer,
JsonConverter converter)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
if (converter == null)
throw new ArgumentNullException("converter");
JObject jObject = JObject.FromObject(value, serializer);
jObject.WriteTo(extends, converter);
}
/// <summary>
/// Writes the type value.
/// </summary>
/// <param name="extends"></param>
/// <param name="type"></param>
[PublicAPI]
public static void WriteType(this JsonWriter extends, Type type)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (type == null)
{
extends.WriteNull();
return;
}
// Find the smallest possible name representation for the type that will still resolve
string name = Type.GetType(type.FullName) == null
? type.AssemblyQualifiedName
: type.FullName;
extends.WriteValue(name);
}
/// <summary>
/// Gets the current value as a Type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Type GetValueAsType(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetValueAsString();
return Type.GetType(value);
}
/// <summary>
/// Gets the current value as an unsigned integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static uint GetValueAsUInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (uint)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int GetValueAsInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (int)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetValueAsString(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String || extends.TokenType == JsonToken.Null)
return extends.Value as string;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.String);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a bool.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetValueAsBool(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Boolean)
return (bool)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an enum.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T GetValueAsEnum<T>(this JsonReader extends)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String)
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
/// <param name="write"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
Action<JsonSerializer, JsonWriter, TItem> write)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
if (write == null)
throw new ArgumentNullException("write");
writer.WriteStartArray();
{
foreach (TItem item in items)
write(extends, writer, item);
}
writer.WriteEndArray();
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
return extends.DeserializeArray(reader, (s, r) => extends.Deserialize<TItem>(reader));
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
/// <param name="read"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader,
Func<JsonSerializer, JsonReader, TItem> read)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (read == null)
throw new ArgumentNullException("read");
if (reader.TokenType == JsonToken.Null)
return Enumerable.Empty<TItem>();
if (reader.TokenType != JsonToken.StartArray)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartArray, reader.TokenType));
return DeserializeArrayIterator(extends, reader, read);
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="serializer"></param>
/// <param name="reader"></param>
/// <param name="read"></param>
private static IEnumerable<TItem> DeserializeArrayIterator<TItem>(JsonSerializer serializer, JsonReader reader,
Func<JsonSerializer, JsonReader, TItem> read)
{
// Step into the first value
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
TItem output = read(serializer, reader);
yield return output;
// Read out of the last value
reader.Read();
}
}
/// <summary>
/// Serializes the given sequence of key-value-pairs to the writer.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeDictionary<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (items == null)
throw new ArgumentNullException("items");
writer.WriteStartObject();
{
foreach (KeyValuePair<TKey, TValue> kvp in items)
{
writer.WritePropertyName(kvp.Key.ToString());
extends.Serialize(writer, kvp.Value);
}
}
writer.WriteEndObject();
}
/// <summary>
/// Deserializes a dictionary of items from the reader's current value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionary<TKey, TValue>(this JsonSerializer extends,
JsonReader reader)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (reader.TokenType == JsonToken.Null)
return Enumerable.Empty<KeyValuePair<TKey, TValue>>();
if (reader.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
return DeserializeDictionaryIterator<TKey, TValue>(extends, reader);
}
/// <summary>
/// Deserializes a dictionary of items from the reader's current value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="serializer"></param>
/// <param name="reader"></param>
private static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionaryIterator<TKey, TValue>(
JsonSerializer serializer, JsonReader reader)
{
// Step into the first key
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
TKey key = (TKey)Convert.ChangeType(reader.Value, typeof(TKey), null);
// Step into the value
reader.Read();
TValue value = serializer.Deserialize<TValue>(reader);
yield return new KeyValuePair<TKey, TValue>(key, value);
// Read out of the last value
reader.Read();
}
}
}
}

View File

@@ -0,0 +1,258 @@
using System;
using ICD.Common.Properties;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with JSON.
/// </summary>
public static class JsonReaderExtensions
{
/// <summary>
/// Reads the current token in the reader and deserializes to the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static T ReadAsObject<T>(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
JsonSerializer serializer =
#if SIMPLSHARP
new JsonSerializer();
#else
JsonSerializer.CreateDefault();
#endif
return extends.ReadAsObject<T>(serializer);
}
/// <summary>
/// Reads the current token in the reader and deserializes to the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public static T ReadAsObject<T>(this JsonReader extends, JsonSerializer serializer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
return serializer.Deserialize<T>(extends);
}
/// <summary>
/// Reads through the current object token and calls the callback for each property value.
/// </summary>
/// <param name="extends"></param>
/// <param name="serializer"></param>
/// <param name="readPropertyValue"></param>
public static void ReadObject(this JsonReader extends, JsonSerializer serializer,
Action<string, JsonReader, JsonSerializer> readPropertyValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
if (readPropertyValue == null)
throw new ArgumentNullException("readPropertyValue");
if (extends.TokenType == JsonToken.Null)
return;
if (extends.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, extends.TokenType));
while (extends.Read())
{
if (extends.TokenType == JsonToken.EndObject)
break;
// Get the property
if (extends.TokenType != JsonToken.PropertyName)
continue;
string property = (string)extends.Value;
// Read into the value
extends.Read();
readPropertyValue(property, extends, serializer);
}
}
/// <summary>
/// Gets the current value as a Type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Type GetValueAsType(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetValueAsString();
return Type.GetType(value);
}
/// <summary>
/// Gets the current value as an unsigned integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static uint GetValueAsUInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (uint)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int GetValueAsInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (int)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetValueAsString(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
#if !SIMPLSHARP
// Newer versions of NewtonSoft try to be helpful and interpret strings as DateTimes without any consideration for different DateTime formats.
if (extends.TokenType == JsonToken.Date && extends.DateParseHandling != DateParseHandling.None)
throw new InvalidOperationException("DateParseHandling needs to be set to None");
#endif
if (!extends.TokenType.IsPrimitive())
throw new FormatException("Expected primitive token type but got " + extends.TokenType);
return extends.Value == null ? null : extends.Value.ToString();
}
/// <summary>
/// Gets the current value as a bool.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetValueAsBool(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Boolean)
return (bool)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an enum.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T GetValueAsEnum<T>(this JsonReader extends)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String)
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
/// <summary>
/// Gets the current value as a guid.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Guid GetValueAsGuid(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string stringValue = extends.GetValueAsString();
return new Guid(stringValue);
}
/// <summary>
/// Gets the current value as a date.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime GetValueAsDateTime(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
#if !SIMPLSHARP
// Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date.
if (extends.DateParseHandling != DateParseHandling.None)
return (DateTime)extends.Value;
#endif
string stringValue = extends.GetValueAsString();
return DateTime.Parse(stringValue);
}
/// <summary>
/// Gets the current value as a date.
/// </summary>
/// <param name="extends"></param>
/// <param name="format"></param>
/// <param name="provider"></param>
/// <returns></returns>
public static DateTime GetValueAsDateTimeExact(this JsonReader extends, string format, IFormatProvider provider)
{
if (extends == null)
throw new ArgumentNullException("extends");
#if !SIMPLSHARP
// Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date.
if (extends.DateParseHandling != DateParseHandling.None)
throw new InvalidOperationException("DateParseHandling needs to be set to None");
#endif
string stringValue = extends.GetValueAsString();
return DateTime.ParseExact(stringValue, format, provider);
}
}
}

View File

@@ -0,0 +1,306 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Extensions
{
public static class JsonSerializerExtensions
{
private const string PROPERTY_KEY = "k";
private const string PROPERTY_VALUE = "v";
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader)
{
return extends.DeserializeArray(reader, (s, r) => extends.Deserialize<TItem>(reader));
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
/// <param name="read"></param>
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader,
Func<JsonSerializer, JsonReader, TItem> read)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (read == null)
throw new ArgumentNullException("read");
if (reader.TokenType == JsonToken.Null)
return Enumerable.Empty<TItem>();
if (reader.TokenType != JsonToken.StartArray)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartArray, reader.TokenType));
// ToArray to ensure everything gets read before moving onto the next token
return DeserializeArrayIterator(extends, reader, read).ToArray();
}
/// <summary>
/// Deserializes an array of items from the reader's current value.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="serializer"></param>
/// <param name="reader"></param>
/// <param name="read"></param>
private static IEnumerable<TItem> DeserializeArrayIterator<TItem>(JsonSerializer serializer, JsonReader reader,
Func<JsonSerializer, JsonReader, TItem> read)
{
// Step into the first value
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
TItem output = read(serializer, reader);
yield return output;
// Step out of the value
reader.Read();
}
}
/// <summary>
/// Deserializes a dictionary of items from the reader's current value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(this JsonSerializer extends,
JsonReader reader)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
return extends.DeserializeDict(reader,
(s, r) => s.Deserialize<TKey>(r),
(s, r) => s.Deserialize<TValue>(r));
}
/// <summary>
/// Deserializes a dictionary of items from the reader's current value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="reader"></param>
/// <param name="readKey"></param>
/// <param name="readValue"></param>
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(this JsonSerializer extends,
JsonReader reader,
Func<JsonSerializer, JsonReader,
TKey> readKey,
Func<JsonSerializer, JsonReader,
TValue> readValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (readKey == null)
throw new ArgumentNullException("readKey");
if (readValue == null)
throw new ArgumentNullException("readValue");
return extends.DeserializeArray(reader, (s, r) => s.DeserializeKeyValuePair(r, readKey, readValue));
}
public static KeyValuePair<TKey, TValue> DeserializeKeyValuePair<TKey, TValue>(this JsonSerializer extends, JsonReader reader,
Func<JsonSerializer, JsonReader,
TKey> readKey,
Func<JsonSerializer, JsonReader,
TValue> readValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (reader == null)
throw new ArgumentNullException("reader");
if (readKey == null)
throw new ArgumentNullException("readKey");
if (readValue == null)
throw new ArgumentNullException("readValue");
if (reader.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
TKey key = default(TKey);
TValue value = default(TValue);
// Step into the first property
reader.Read();
while (reader.TokenType != JsonToken.EndObject)
{
if (reader.TokenType != JsonToken.PropertyName)
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.PropertyName, reader.TokenType));
string propertyName = (string)reader.Value;
// Step into the value
reader.Read();
switch (propertyName)
{
case PROPERTY_KEY:
key = readKey(extends, reader);
break;
case PROPERTY_VALUE:
value = readValue(extends, reader);
break;
default:
throw new FormatException(string.Format("Unexpected property {0}", reader.Value));
}
// Step out of the value
reader.Read();
}
return new KeyValuePair<TKey, TValue>(key, value);
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
{
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
/// <param name="write"></param>
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
Action<JsonSerializer, JsonWriter, TItem> write)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (write == null)
throw new ArgumentNullException("write");
if (items == null)
{
writer.WriteNull();
return;
}
writer.WriteStartArray();
{
foreach (TItem item in items)
write(extends, writer, item);
}
writer.WriteEndArray();
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
public static void SerializeDict<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
extends.SerializeDict(writer, items,
(s, w, k) => s.Serialize(w, k),
(s, w, v) => s.Serialize(w, v));
}
/// <summary>
/// Serializes the given sequence of items to the writer.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="writer"></param>
/// <param name="items"></param>
/// <param name="writeKey"></param>
/// <param name="writeValue"></param>
public static void SerializeDict<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
IEnumerable<KeyValuePair<TKey, TValue>> items,
Action<JsonSerializer, JsonWriter, TKey> writeKey,
Action<JsonSerializer, JsonWriter, TValue> writeValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (writeKey == null)
throw new ArgumentNullException("writeKey");
if (writeValue == null)
throw new ArgumentNullException("writeValue");
extends.SerializeArray(writer, items, (s, w, kvp) => s.SerializeKeyValuePair(w, kvp, writeKey, writeValue));
}
public static void SerializeKeyValuePair<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
KeyValuePair<TKey, TValue> kvp,
Action<JsonSerializer, JsonWriter, TKey> writeKey,
Action<JsonSerializer, JsonWriter, TValue> writeValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
if (writeKey == null)
throw new ArgumentNullException("writeKey");
if (writeValue == null)
throw new ArgumentNullException("writeValue");
writer.WriteStartObject();
{
writer.WritePropertyName(PROPERTY_KEY);
writeKey(extends, writer, kvp.Key);
writer.WritePropertyName(PROPERTY_VALUE);
writeValue(extends, writer, kvp.Value);
}
writer.WriteEndObject();
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Extensions
{
public static class JsonTokenExtensions
{
/// <summary>
/// Returns true if the JsonToken respresents a single data value
/// rather than a complex type such as an object or an array.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsPrimitive(this JsonToken extends)
{
switch (extends)
{
case JsonToken.None:
case JsonToken.StartObject:
case JsonToken.StartArray:
case JsonToken.StartConstructor:
case JsonToken.EndObject:
case JsonToken.EndArray:
case JsonToken.EndConstructor:
case JsonToken.Undefined:
return false;
case JsonToken.PropertyName:
case JsonToken.Comment:
case JsonToken.Raw:
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return true;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
}
}

View File

@@ -0,0 +1,135 @@
using System;
using ICD.Common.Properties;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Extensions
{
public static class JsonWriterExtensions
{
/// <summary>
/// Writes the type value.
/// </summary>
/// <param name="extends"></param>
/// <param name="type"></param>
[PublicAPI]
public static void WriteType(this JsonWriter extends, Type type)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (type == null)
{
extends.WriteNull();
return;
}
string name = type.GetMinimalName();
extends.WriteValue(name);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, object value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, string value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, DateTime value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, bool value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, int value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, Guid value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteValue(value);
}
/// <summary>
/// Writes the property name and value to the writer.
/// </summary>
/// <param name="extends"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
public static void WriteProperty(this JsonWriter extends, string propertyName, Type value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteType(value);
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Comparers;
@@ -18,7 +17,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddSorted<T>(this List<T> extends, IEnumerable<T> items)
public static void AddSorted<T>(this IList<T> extends, IEnumerable<T> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -37,7 +36,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <param name="comparer"></param>
[PublicAPI]
public static void AddSorted<T>(this List<T> extends, IEnumerable<T> items, IComparer<T> comparer)
public static void AddSorted<T>(this IList<T> extends, IEnumerable<T> items, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -60,7 +59,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <param name="predicate"></param>
[PublicAPI]
public static void AddSorted<T, TProp>(this List<T> extends, IEnumerable<T> items, Func<T, TProp> predicate)
public static void AddSorted<T, TProp>(this IList<T> extends, IEnumerable<T> items, Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -82,7 +81,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item"></param>
[PublicAPI]
public static int AddSorted<T>(this List<T> extends, T item)
public static int AddSorted<T>(this IList<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -98,7 +97,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="item"></param>
/// <param name="comparer"></param>
[PublicAPI]
public static int AddSorted<T>(this List<T> extends, T item, IComparer<T> comparer)
public static int AddSorted<T>(this IList<T> extends, T item, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -124,7 +123,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="item"></param>
/// <param name="predicate"></param>
[PublicAPI]
public static int AddSorted<T, TProp>(this List<T> extends, T item, Func<T, TProp> predicate)
public static int AddSorted<T, TProp>(this IList<T> extends, T item, Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -137,44 +136,40 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Pads the list to the given total length.
/// Returns the index of the item in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="totalLength"></param>
[PublicAPI]
public static void PadRight<T>(this List<T> extends, int totalLength)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (totalLength < 0)
throw new ArgumentOutOfRangeException("totalLength", "totalLength must be greater or equal to 0");
extends.PadRight(totalLength, default(T));
}
/// <summary>
/// Pads the list to the given total length with the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="totalLength"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static void PadRight<T>(this List<T> extends, int totalLength, T item)
public static int BinarySearch<T>(this IList<T> extends, T item, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (totalLength < 0)
throw new ArgumentOutOfRangeException("totalLength", "totalLength must be greater or equal to 0");
if (comparer == null)
throw new ArgumentNullException("comparer");
int pad = totalLength - extends.Count;
if (pad <= 0)
return;
int lo = 0;
int hi = extends.Count - 1;
extends.AddRange(Enumerable.Repeat(item, pad));
while (lo <= hi)
{
int i = lo + ((hi - lo) >> 1);
int order = comparer.Compare(extends[i], item);
if (order == 0)
return i;
if (order < 0)
lo = i + 1;
else
hi = i - 1;
}
return ~lo;
}
}
}

View File

@@ -71,7 +71,10 @@ namespace ICD.Common.Utils.Extensions
sigBuilder.Append("(");
firstParam = true;
#if !SIMPLSHARP
bool secondParam = false;
#endif
foreach (ParameterInfo param in method.GetParameters())
{

View File

@@ -43,5 +43,26 @@ namespace ICD.Common.Utils.Extensions
item = extends.Dequeue();
return true;
}
/// <summary>
/// Peeks the next item in the queue. Returns false if the queue is empty.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool Peek<T>(this Queue<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
item = default(T);
if (extends.Count == 0)
return false;
item = extends.Peek();
return true;
}
}
}

View File

@@ -21,7 +21,6 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -37,7 +36,6 @@ namespace ICD.Common.Utils.Extensions
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends, bool inherits)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -60,7 +58,6 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -76,7 +73,6 @@ namespace ICD.Common.Utils.Extensions
/// <param name="inherits"></param>
/// <returns></returns>
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends, bool inherits)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -37,6 +37,9 @@ namespace ICD.Common.Utils.Extensions
index = thisIndex;
first = item;
if (index == 0)
break;
}
return index;
@@ -149,7 +152,31 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Removes the given characters from the string.
/// Removes all occurances of the given string.
/// </summary>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
public static string Remove(this string extends, string other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
if (string.IsNullOrEmpty(other))
return extends;
int index;
while ((index = extends.IndexOf(other, StringComparison.Ordinal)) >= 0)
extends = extends.Remove(index, other.Length);
return extends;
}
/// <summary>
/// Removes all occurances the given characters from the string.
/// </summary>
/// <param name="extends"></param>
/// <param name="characters"></param>
@@ -162,8 +189,9 @@ namespace ICD.Common.Utils.Extensions
if (characters == null)
throw new ArgumentNullException("characters");
var cSet = characters.ToIcdHashSet();
return new string(extends.Except(characters).ToArray());
return new string(extends.Where(c => !cSet.Contains(c)).ToArray());
}
/// <summary>
@@ -193,5 +221,29 @@ namespace ICD.Common.Utils.Extensions
return extends.Contains(character.ToString());
}
/// <summary>
/// Generates a hashcode that is consistent between program executions.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static int GetStableHashCode(this string extends)
{
unchecked
{
int hash1 = 5381;
int hash2 = hash1;
for (int i = 0; i < extends.Length && extends[i] != '\0'; i += 2)
{
hash1 = ((hash1 << 5) + hash1) ^ extends[i];
if (i == extends.Length - 1 || extends[i + 1] == '\0')
break;
hash2 = ((hash2 << 5) + hash2) ^ extends[i + 1];
}
return hash1 + (hash2 * 1566083941);
}
}
}
}

View File

@@ -25,5 +25,48 @@ namespace ICD.Common.Utils.Extensions
return builder.ToString();
}
/// <summary>
/// Adds the given number of hours to the time, wrapping every 24 hours without modifying the day.
/// </summary>
/// <param name="extends"></param>
/// <param name="hours"></param>
/// <returns></returns>
public static TimeSpan AddHoursAndWrap(this TimeSpan extends, int hours)
{
hours = MathUtils.Modulus(hours + extends.Hours, 24);
return new TimeSpan(extends.Days, hours, extends.Minutes, extends.Seconds, extends.Milliseconds);
}
/// <summary>
/// Adds the given number of hours to the time, wrapping within the current 12 hour span, without modifying the day.
/// </summary>
/// <param name="extends"></param>
/// <param name="hours"></param>
/// <returns></returns>
public static TimeSpan AddHoursAndWrap12Hour(this TimeSpan extends, int hours)
{
int currentHour = extends.Hours;
bool am = extends.Hours < 12;
int current12Hour = MathUtils.Modulus(currentHour, 12);
int new12Hour = MathUtils.Modulus(current12Hour + hours, 12);
return am
? new TimeSpan(extends.Days, new12Hour, extends.Minutes, extends.Seconds, extends.Milliseconds)
: new TimeSpan(extends.Days, new12Hour + 12, extends.Minutes, extends.Seconds, extends.Milliseconds);
}
/// <summary>
/// Adds the given number of minutes to the time, wrapping every 60 minutes without modifying the hour.
/// </summary>
/// <param name="extends"></param>
/// <param name="minutes"></param>
/// <returns></returns>
public static TimeSpan AddMinutesAndWrap(this TimeSpan extends, int minutes)
{
minutes = MathUtils.Modulus(minutes + extends.Minutes, 60);
return new TimeSpan(extends.Days, extends.Hours, minutes, extends.Seconds, extends.Milliseconds);
}
}
}

View File

@@ -62,6 +62,8 @@ namespace ICD.Common.Utils.Extensions
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
/// <summary>
/// Static constructor.
@@ -72,6 +74,8 @@ namespace ICD.Common.Utils.Extensions
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
s_TypeToMinimalName = new Dictionary<Type, string>();
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
}
/// <summary>
@@ -158,6 +162,19 @@ namespace ICD.Common.Utils.Extensions
.Assembly;
}
/// <summary>
/// Returns true if the type is assignable to the given type.
/// </summary>
/// <param name="from"></param>
/// <returns></returns>
public static bool IsAssignableTo<T>(this Type from)
{
if (from == null)
throw new ArgumentNullException("from");
return from.IsAssignableTo(typeof(T));
}
/// <summary>
/// Returns true if the type is assignable to the given type.
/// </summary>
@@ -307,6 +324,127 @@ namespace ICD.Common.Utils.Extensions
return index == -1 ? name : name.Substring(0, index);
}
/// <summary>
/// Gets the smallest possible string representation for the given type that
/// can be converted back to a Type via Type.GetType(string).
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string GetMinimalName(this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string name;
if (!s_TypeToMinimalName.TryGetValue(extends, out name))
{
// Generics are a pain
if (extends.IsGenericType)
{
string nameWithoutAssemblyDetails = Type.GetType(extends.FullName) == null
? extends.GetNameWithoutAssemblyDetails()
: extends.FullName;
int genericStart = nameWithoutAssemblyDetails.IndexOf('[');
if (genericStart < 0)
{
name = nameWithoutAssemblyDetails;
}
else
{
string genericParameterNames =
string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray());
int genericEnd = nameWithoutAssemblyDetails.LastIndexOf(']');
name = new StringBuilder().Append(nameWithoutAssemblyDetails, 0, genericStart + 2)
.Append(genericParameterNames)
.Append(nameWithoutAssemblyDetails, genericEnd - 1,
nameWithoutAssemblyDetails.Length - genericEnd + 1)
.ToString();
}
}
else
{
name = Type.GetType(extends.FullName) == null
? extends.GetNameWithoutAssemblyDetails()
: extends.FullName;
}
s_TypeToMinimalName[extends] = name;
}
return name;
}
/// <summary>
/// Gets the string representation for the type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string GetNameWithoutAssemblyDetails(this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string name;
if (!s_TypeToNameWithoutAssemblyDetails.TryGetValue(extends, out name))
{
name = RemoveAssemblyDetails(extends.AssemblyQualifiedName);
s_TypeToNameWithoutAssemblyDetails[extends] = name;
}
return name;
}
/// <summary>
/// Taken from Newtonsoft.Json.Utilities.ReflectionUtils
/// Removes the assembly details from a type assembly qualified name.
/// </summary>
/// <param name="fullyQualifiedTypeName"></param>
/// <returns></returns>
private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
{
StringBuilder builder = new StringBuilder();
// loop through the type name and filter out qualified assembly details from nested type names
bool writingAssemblyName = false;
bool skippingAssemblyDetails = false;
foreach (char current in fullyQualifiedTypeName)
{
switch (current)
{
case '[':
writingAssemblyName = false;
skippingAssemblyDetails = false;
builder.Append(current);
break;
case ']':
writingAssemblyName = false;
skippingAssemblyDetails = false;
builder.Append(current);
break;
case ',':
if (!writingAssemblyName)
{
writingAssemblyName = true;
builder.Append(current);
}
else
{
skippingAssemblyDetails = true;
}
break;
default:
if (!skippingAssemblyDetails)
{
builder.Append(current);
}
break;
}
}
return builder.ToString();
}
/// <summary>
/// Gets the type name as it would appear in code.
/// </summary>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
using System;
namespace ICD.Common.Utils
{
public static class GuidUtils
{
public static Guid GenerateSeeded(int seed)
{
Random seeded = new Random(seed);
byte[] bytes = new byte[16];
seeded.NextBytes(bytes);
return new Guid(bytes);
}
}
}

View File

@@ -39,11 +39,16 @@
<None Remove="Properties\ControlSystem.cfg" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SQLite" Version="2.1.0" />
<PackageReference Include="Microsoft.Data.SQLite" Version="2.2.6" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<None Update="CultureInfo.sqlite">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -75,8 +75,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\AbstractIcdAttribute.cs" />
<Compile Include="Attributes\IIcdAttribute.cs" />
<Compile Include="Attributes\RangeAttribute.cs" />
<Compile Include="Collections\BiDictionary.cs" />
<Compile Include="Collections\AsyncEventQueue.cs" />
<Compile Include="Collections\IcdOrderedDictionary.cs" />
<Compile Include="Collections\PriorityQueue.cs" />
<Compile Include="Collections\RateLimitedEventQueue.cs" />
@@ -85,9 +86,11 @@
<Compile Include="Comparers\PredicateComparer.cs" />
<Compile Include="Comparers\SequenceComparer.cs" />
<Compile Include="ConsoleColor.cs" />
<Compile Include="DateTimeUtils.cs" />
<Compile Include="Email\EmailClient.cs" />
<Compile Include="Email\eMailErrorCode.cs" />
<Compile Include="Email\EmailStringCollection.cs" />
<Compile Include="Email\EmailValidation.cs" />
<Compile Include="EncodingUtils.cs" />
<Compile Include="Csv\CsvWriter.cs" />
<Compile Include="Csv\CsvWriterSettings.cs" />
@@ -101,21 +104,31 @@
<Compile Include="EventArguments\StringEventArgs.cs" />
<Compile Include="EventArguments\UShortEventArgs.cs" />
<Compile Include="EventArguments\XmlRecursionEventArgs.cs" />
<None Include="CultureInfo.sqlite">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ObfuscationSettings.cs" />
<Compile Include="Extensions\BoolExtensions.cs" />
<Compile Include="Extensions\ByteExtensions.cs" />
<Compile Include="Extensions\CultureInfoExtensions.cs" />
<Compile Include="Extensions\DayOfWeekExtensions.cs" />
<Compile Include="Extensions\JsonSerializerExtensions.cs" />
<Compile Include="Extensions\JsonTokenExtensions.cs" />
<Compile Include="Extensions\JsonWriterExtensions.cs" />
<Compile Include="Extensions\ListExtensions.cs" />
<Compile Include="Comparers\PredicateEqualityComparer.cs" />
<Compile Include="Extensions\MethodInfoExtensions.cs" />
<Compile Include="Extensions\ParameterInfoExtensions.cs" />
<Compile Include="Extensions\UriExtensions.cs" />
<Compile Include="Extensions\UshortExtensions.cs" />
<Compile Include="Extensions\UShortExtensions.cs" />
<Compile Include="Globalization\IcdCultureInfo.cs" />
<Compile Include="GuidUtils.cs" />
<Compile Include="IcdUriBuilder.cs" />
<Compile Include="IO\Compression\IcdZipEntry.cs" />
<Compile Include="IO\IcdBinaryReader.cs" />
<Compile Include="IO\eSeekOrigin.cs" />
<Compile Include="IO\IcdStreamWriter.cs" />
<Compile Include="Json\ToStringJsonConverter.cs" />
<Compile Include="ProcessorUtils.SimplSharp.cs" />
<Compile Include="ProcessorUtils.Standard.cs" />
<Compile Include="ProgramUtils.SimplSharp.cs" />
@@ -153,7 +166,7 @@
<Compile Include="Extensions\EnumerableExtensions.cs" />
<Compile Include="Extensions\EnumExtensions.cs" />
<Compile Include="Extensions\EventHandlerExtensions.cs" />
<Compile Include="Extensions\JsonExtensions.cs" />
<Compile Include="Extensions\JsonReaderExtensions.cs" />
<Compile Include="Extensions\QueueExtensions.cs" />
<Compile Include="Extensions\ReflectionExtensions.cs" />
<Compile Include="Extensions\StringBuilderExtensions.cs" />
@@ -184,6 +197,7 @@
<Compile Include="SafeCriticalSection.SimplSharp.cs" />
<Compile Include="SafeCriticalSection.Standard.cs" />
<Compile Include="SafeMutex.cs" />
<Compile Include="SPlusUtils.cs" />
<Compile Include="Sqlite\eDbType.cs" />
<Compile Include="Sqlite\IcdDbDataReader.cs" />
<Compile Include="Sqlite\IcdSqliteCommand.cs" />
@@ -201,6 +215,7 @@
<Compile Include="Timers\Repeater.cs" />
<Compile Include="Timers\SafeTimer.cs" />
<Compile Include="TryUtils.cs" />
<Compile Include="UriQueryBuilder.cs" />
<Compile Include="UriUtils.cs" />
<Compile Include="Xml\AbstractGenericXmlConverter.cs" />
<Compile Include="Xml\AbstractXmlConverter.cs" />
@@ -210,7 +225,6 @@
<Compile Include="Xml\IcdXmlException.cs" />
<Compile Include="Xml\IcdXmlReader.cs" />
<Compile Include="Xml\IcdXmlTextWriter.cs" />
<Compile Include="Xml\IcdXmlAttribute.cs" />
<Compile Include="Xml\IXmlConverter.cs" />
<Compile Include="Xml\XmlConverterAttribute.cs" />
<Compile Include="Xml\XmlReaderExtensions.cs" />

View File

@@ -2,6 +2,7 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using ICD.Common.Utils.Extensions;
using System.IO;
using Microsoft.DotNet.PlatformAbstractions;
#endif
@@ -19,6 +20,19 @@ namespace ICD.Common.Utils.IO
#endif
}
/// <summary>
/// This gets the application root directory for Crestron systems
/// </summary>
/// <returns></returns>
public static string GetApplicationRootDirectory()
{
#if SIMPLSHARP
return Directory.GetApplicationRootDirectory();
#else
return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetPath());
#endif
}
public static bool Exists(string path)
{
if (path == null)

View File

@@ -17,5 +17,10 @@ namespace ICD.Common.Utils.IO
public IcdStreamWriter(StreamWriter baseStreamWriter) : base(baseStreamWriter)
{
}
public void WriteLine(string value)
{
WrappedStreamWriter.WriteLine(value);
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.EventArguments;
using ICD.Common.Utils.Extensions;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
@@ -18,6 +20,8 @@ namespace ICD.Common.Utils
Administrator = 2
}
public static event EventHandler<StringEventArgs> OnConsolePrint;
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
@@ -41,26 +45,34 @@ namespace ICD.Common.Utils
message = string.Format(message, args);
#if SIMPLSHARP
try
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpPro)
{
CrestronConsole.ConsoleCommandResponse(message);
try
{
CrestronConsole.ConsoleCommandResponse(message);
}
catch (NotSupportedException)
{
PrintLine(message);
}
return;
}
catch (NotSupportedException)
{
Print(message);
}
#else
Print(message, args);
#endif
PrintLine(message);
}
public static void PrintLine(string message)
{
#if SIMPLSHARP
CrestronConsole.PrintLine(message);
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
CrestronConsole.PrintLine(message);
#else
Console.WriteLine(message);
#endif
OnConsolePrint.Raise(null, new StringEventArgs(message + IcdEnvironment.NewLine));
}
public static void PrintLine(string message, params object[] args)
@@ -90,10 +102,12 @@ namespace ICD.Common.Utils
public static void Print(string message)
{
#if SIMPLSHARP
CrestronConsole.Print(message);
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
CrestronConsole.Print(message);
#else
Console.Write(message);
#endif
OnConsolePrint.Raise(null, new StringEventArgs(message));
}
public static void Print(string message, params object[] args)
@@ -123,6 +137,10 @@ namespace ICD.Common.Utils
public static bool SendControlSystemCommand(string command, ref string result)
{
#if SIMPLSHARP
// No console on VC4
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
return false;
return CrestronConsole.SendControlSystemCommand(command, ref result);
#else
return false;

View File

@@ -1,4 +1,5 @@
#if SIMPLSHARP
using ICD.Common.Utils.Extensions;
#if SIMPLSHARP
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
@@ -12,7 +13,12 @@ namespace ICD.Common.Utils
public static eRuntimeEnvironment RuntimeEnvironment
{
get { return GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment); }
get
{
return CrestronEnvironment.DevicePlatform == eDevicePlatform.Server
? eRuntimeEnvironment.SimplSharpProMono
: GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment);
}
}
/// <summary>
@@ -25,9 +31,36 @@ namespace ICD.Common.Utils
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
string address1 = null;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
address1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(address1))
yield return address1;
string address2 = null;
try
{
short adapter2Type = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
address2 = CrestronEthernetHelper.GetEthernetParameter(param, adapter2Type);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(address2))
yield return address2;
}
}
@@ -41,9 +74,104 @@ namespace ICD.Common.Utils
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS;
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
string macAddress1 = null;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
macAddress1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(macAddress1))
yield return macAddress1;
string macAddress2 = null;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
macAddress2 = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(macAddress2))
yield return macAddress2;
}
}
/// <summary>
/// Gets the dhcp status of the processor.
/// </summary>
[PublicAPI]
public static string DhcpStatus
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
return CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
return null;
}
}
}
/// <summary>
/// Gets the hostname of the processor.
/// </summary>
[PublicAPI]
public static IEnumerable<string> Hostname
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME;
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
string address1 = null;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
address1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(address1))
yield return address1;
string address2 = null;
try
{
short adapter2Type = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
address2 = CrestronEthernetHelper.GetEthernetParameter(param, adapter2Type);
}
catch (ArgumentException)
{
}
if (!string.IsNullOrEmpty(address2))
yield return address2;
}
}
@@ -63,6 +191,18 @@ namespace ICD.Common.Utils
return CrestronEnvironment.GetLocalTime();
}
public static void SetLocalTime(DateTime localTime)
{
CrestronEnvironment.SetTimeAndDate((ushort)localTime.Hour,
(ushort)localTime.Minute,
(ushort)localTime.Second,
(ushort)localTime.Month,
(ushort)localTime.Day,
(ushort)localTime.Year);
OnSystemDateTimeChanged.Raise(null);
}
public static eEthernetEventType GetEthernetEventType(Crestron.SimplSharp.eEthernetEventType type)
{
switch (type)

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
@@ -13,11 +14,6 @@ namespace ICD.Common.Utils
{
public static string NewLine { get { return Environment.NewLine; } }
public static DateTime GetLocalTime()
{
return DateTime.Now;
}
public static eRuntimeEnvironment RuntimeEnvironment { get { return eRuntimeEnvironment.Standard; } }
/// <summary>
@@ -53,6 +49,48 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Gets the dhcp status of the processor.
/// </summary>
[PublicAPI]
public static string DhcpStatus
{
get
{
bool enabled =
NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.Select(ni => ni.GetIPProperties().GetIPv4Properties().IsDhcpEnabled)
.FirstOrDefault();
return enabled.ToString();
}
}
/// <summary>
/// Gets the hostname of the processor.
/// </summary>
[PublicAPI]
public static IEnumerable<string> Hostname { get { yield return Dns.GetHostName(); } }
public static DateTime GetLocalTime()
{
return DateTime.Now;
}
public static void SetLocalTime(DateTime localTime)
{
#if DEBUG
IcdConsole.PrintLine(eConsoleColor.Magenta, "Debug Build - Skipped setting local time to {0}",
localTime.ToString("s"));
#else
throw new NotSupportedException();
OnSystemDateTimeChanged.Raise(null);
#endif
}
/// <summary>
/// Converts 12 digit address to XX:XX:XX... format
/// </summary>

View File

@@ -1,4 +1,6 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
@@ -11,6 +13,7 @@ namespace ICD.Common.Utils
{
SimplSharp,
SimplSharpPro,
SimplSharpProMono,
Standard
}
@@ -53,5 +56,46 @@ namespace ICD.Common.Utils
public static event ProgramStatusCallback OnProgramStatusEvent;
public static event EthernetEventCallback OnEthernetEvent;
/// <summary>
/// Raised when the program has completed initialization.
/// </summary>
public static event EventHandler OnProgramInitializationComplete;
/// <summary>
/// Raised when the system date/time has been set.
/// </summary>
public static event EventHandler OnSystemDateTimeChanged;
private static readonly SafeCriticalSection s_ProgramInitializationSection = new SafeCriticalSection();
private static bool s_ProgramInitializationComplete;
/// <summary>
/// Returns true if the program has been flagged as completely initialized.
/// </summary>
public static bool ProgramIsInitialized { get { return s_ProgramInitializationSection.Execute(() => s_ProgramInitializationComplete); } }
/// <summary>
/// Called by the program entry point to signify that the program initialization is complete.
/// </summary>
[PublicAPI]
public static void SetProgramInitializationComplete()
{
s_ProgramInitializationSection.Enter();
try
{
if (s_ProgramInitializationComplete)
return;
s_ProgramInitializationComplete = true;
}
finally
{
s_ProgramInitializationSection.Leave();
}
OnProgramInitializationComplete.Raise(null);
}
}
}

View File

@@ -26,12 +26,13 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_RED);
message = eConsoleColor.Red.FormatAnsi(message);
ErrorLog.Error(message);
#else
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Write("Error - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine(message);
Console.ResetColor();
#endif
}
finally
@@ -54,12 +55,13 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW);
message = eConsoleColor.Yellow.FormatAnsi(message);
ErrorLog.Warn(message);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Write("Warn - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Error.WriteLine(message);
Console.ResetColor();
#endif
}
finally
@@ -82,12 +84,13 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_BLUE);
message = eConsoleColor.Blue.FormatAnsi(message);
ErrorLog.Notice(message);
#else
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Write("Notice - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Blue;
Console.Error.WriteLine(message);
Console.ResetColor();
#endif
}
finally
@@ -110,12 +113,13 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_GREEN);
message = eConsoleColor.Green.FormatAnsi(message);
ErrorLog.Ok(message);
#else
System.Console.ForegroundColor = ConsoleColor.Green;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Write("OK - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Green;
Console.Error.WriteLine(message);
Console.ResetColor();
#endif
}
finally
@@ -138,14 +142,15 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW_ON_RED_BACKGROUND);
message = eConsoleColor.YellowOnRed.FormatAnsi(message);
ErrorLog.Exception(message, ex);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.BackgroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
System.Console.ResetColor();
System.Console.Error.WriteLine(ex.StackTrace);
Console.Write("Except - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Yellow;
Console.BackgroundColor = ConsoleColor.Red;
Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
Console.ResetColor();
Console.Error.WriteLine(ex.StackTrace);
#endif
}
finally
@@ -169,12 +174,13 @@ namespace ICD.Common.Utils
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_CYAN);
message = eConsoleColor.Cyan.FormatAnsi(message);
ErrorLog.Info(message);
#else
System.Console.ForegroundColor = ConsoleColor.Cyan;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Write("Info - {0} - ", IcdEnvironment.GetLocalTime());
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Error.WriteLine(message);
Console.ResetColor();
#endif
}
finally
@@ -188,16 +194,5 @@ namespace ICD.Common.Utils
{
Info(string.Format(message, args));
}
/// <summary>
/// Formats the text with the given console color.
/// </summary>
/// <param name="text"></param>
/// <param name="color"></param>
/// <returns></returns>
private static string FormatConsoleColor(string text, string color)
{
return string.Format("{0}{1}{2}", color, text, ConsoleColorExtensions.CONSOLE_RESET);
}
}
}

View File

@@ -1,5 +1,9 @@
using System;
#if !SIMPLSHARP
using System.Linq;
#endif
using System.Text;
using System.Text.RegularExpressions;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
@@ -9,6 +13,8 @@ namespace ICD.Common.Utils
/// </summary>
public sealed class IcdUriBuilder
{
private string m_Query;
#region Properties
/// <summary>
@@ -39,7 +45,7 @@ namespace ICD.Common.Utils
/// <summary>
/// Gets or sets any query information included in the URI.
/// </summary>
public string Query { get; set; }
public string Query { get { return string.IsNullOrEmpty(m_Query) ? string.Empty : "?" + m_Query; } set { m_Query = value; } }
/// <summary>
/// Gets or sets the scheme name of the URI.
@@ -62,6 +68,7 @@ namespace ICD.Common.Utils
/// Constructor.
/// </summary>
public IcdUriBuilder()
: this(new Uri("http://localhost/"))
{
}
@@ -80,6 +87,9 @@ namespace ICD.Common.Utils
/// <param name="uri"></param>
public IcdUriBuilder(Uri uri)
{
if (uri == null)
throw new ArgumentNullException("uri");
if (!uri.IsAbsoluteUri)
uri = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri);
@@ -88,7 +98,7 @@ namespace ICD.Common.Utils
Password = uri.GetPassword();
Path = uri.AbsolutePath;
Port = (ushort)uri.Port;
Query = uri.Query;
Query = uri.Query.TrimStart('?');
Scheme = uri.Scheme;
UserName = uri.GetUserName();
}
@@ -99,20 +109,20 @@ namespace ICD.Common.Utils
/// <returns></returns>
public override string ToString()
{
// URI = scheme:[//authority]path[?query][#fragment]
// URI = [scheme://][authority]path[?query][#fragment]
// authority = [userinfo@]host[:port]
// userinfo = username[:password]
StringBuilder builder = new StringBuilder();
// Scheme
string scheme = string.IsNullOrEmpty(Scheme) ? Uri.UriSchemeHttp : Scheme;
builder.Append(scheme);
builder.Append(':');
if (!string.IsNullOrEmpty(Scheme))
{
builder.Append(Scheme);
builder.Append("://");
}
// Authority
builder.Append("//");
if (!string.IsNullOrEmpty(UserName))
{
builder.Append(UserName);
@@ -126,8 +136,7 @@ namespace ICD.Common.Utils
builder.Append('@');
}
string host = string.IsNullOrEmpty(Host) ? "localhost" : Host;
builder.Append(host);
builder.Append(Host);
if (Port != 0)
{
@@ -142,10 +151,7 @@ namespace ICD.Common.Utils
// Query
if (!string.IsNullOrEmpty(Query))
{
builder.Append('?');
builder.Append(Query);
}
// Fragment
if (!string.IsNullOrEmpty(Fragment))
@@ -155,6 +161,125 @@ namespace ICD.Common.Utils
}
return builder.ToString();
}
/// <summary>
/// Appends the given path to the current path, ensuring only one separator between parts.
/// </summary>
/// <param name="parts"></param>
/// <returns></returns>
public void AppendPath(params string[] parts)
{
parts = parts.Prepend(Path).ToArray(parts.Length + 1);
Path = Combine(parts);
}
#region Flurl
// The following region is taken from Flurl https://github.com/tmenier/Flurl
/*
MIT License
Copyright (c) 2018 Todd Menier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/// <summary>
/// Basically a Path.Combine for URLs. Ensures exactly one '/' seperates each segment,
/// and exactly on '&amp;' seperates each query parameter.
/// URL-encodes illegal characters but not reserved characters.
/// </summary>
/// <param name="parts">URL parts to combine.</param>
public static string Combine(params string[] parts)
{
if (parts == null)
throw new ArgumentNullException("parts");
string result = "";
bool inQuery = false, inFragment = false;
foreach (var part in parts)
{
if (string.IsNullOrEmpty(part))
continue;
if (result.EndsWith("?") || part.StartsWith("?"))
result = CombineEnsureSingleSeperator(result, part, '?');
else if (result.EndsWith("#") || part.StartsWith("#"))
result = CombineEnsureSingleSeperator(result, part, '#');
else if (inFragment)
result += part;
else if (inQuery)
result = CombineEnsureSingleSeperator(result, part, '&');
else
result = CombineEnsureSingleSeperator(result, part, '/');
if (part.Contains("#"))
{
inQuery = false;
inFragment = true;
}
else if (!inFragment && part.Contains("?"))
{
inQuery = true;
}
}
return EncodeIllegalCharacters(result, false);
}
private static string CombineEnsureSingleSeperator(string a, string b, char seperator)
{
if (string.IsNullOrEmpty(a)) return b;
if (string.IsNullOrEmpty(b)) return a;
return a.TrimEnd(seperator) + seperator + b.TrimStart(seperator);
}
/// <summary>
/// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
/// </summary>
/// <param name="s">The string to encode.</param>
/// <param name="encodeSpaceAsPlus">If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.</param>
/// <returns>The encoded URL.</returns>
private static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus) {
if (string.IsNullOrEmpty(s))
return s;
if (encodeSpaceAsPlus)
s = s.Replace(" ", "+");
// Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
// in that % isn't illegal if it's the start of a %-encoded sequence https://stackoverflow.com/a/47636037/62600
// no % characters, so avoid the regex overhead
if (!s.Contains("%"))
return Uri.EscapeUriString(s);
// pick out all %-hex-hex matches and avoid double-encoding
return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
return Uri.EscapeUriString(a) + b;
});
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Json
@@ -10,7 +11,10 @@ namespace ICD.Common.Utils.Json
/// Creates a new instance of T.
/// </summary>
/// <returns></returns>
protected abstract T Instantiate();
protected virtual T Instantiate()
{
return ReflectionUtils.CreateInstance<T>();
}
/// <summary>
/// Writes the JSON representation of the object.
@@ -26,12 +30,6 @@ namespace ICD.Common.Utils.Json
if (serializer == null)
throw new ArgumentNullException("serializer");
if (value == null)
{
writer.WriteNull();
return;
}
WriteJson(writer, (T)value, serializer);
}
@@ -50,12 +48,25 @@ namespace ICD.Common.Utils.Json
if (serializer == null)
throw new ArgumentNullException("serializer");
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
{
writer.WriteNull();
return;
}
WriteObject(writer, value, serializer);
}
/// <summary>
/// Override to write the object value to the writer.
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
protected virtual void WriteObject(JsonWriter writer, T value, JsonSerializer serializer)
{
writer.WriteStartObject();
{
WriteProperties(writer, value, serializer);
@@ -92,7 +103,10 @@ namespace ICD.Common.Utils.Json
if (serializer == null)
throw new ArgumentNullException("serializer");
return ReadJson(reader, (T)existingValue, serializer);
// Casting null blows up struct casts
T cast = (T)(existingValue ?? default(T));
return ReadJson(reader, cast, serializer);
}
/// <summary>
@@ -113,30 +127,26 @@ namespace ICD.Common.Utils.Json
if (serializer == null)
throw new ArgumentNullException("serializer");
T output = default(T);
bool instantiated = false;
if (reader.TokenType == JsonToken.Null)
return default(T);
while (reader.Read())
{
if (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.EndObject)
break;
if (reader.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, reader.TokenType));
if (!instantiated)
{
instantiated = true;
output = Instantiate();
}
return ReadObject(reader, serializer);
}
// Get the property
if (reader.TokenType != JsonToken.PropertyName)
continue;
string property = (string)reader.Value;
/// <summary>
/// Override to handle deserialization of the current StartObject token.
/// </summary>
/// <param name="reader"></param>
/// <param name="serializer"></param>
/// <returns></returns>
protected virtual T ReadObject(JsonReader reader, JsonSerializer serializer)
{
T output = Instantiate();
// Read into the value
reader.Read();
ReadProperty(property, reader, output, serializer);
}
reader.ReadObject(serializer, (p, r, s) => ReadProperty(p, r, output, s));
return output;
}

View File

@@ -1,12 +1,10 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ICD.Common.Utils.Json
{
@@ -16,102 +14,9 @@ namespace ICD.Common.Utils.Json
[PublicAPI]
public static class JsonUtils
{
// 2016-02-26T19:24:59
private const string DATE_FORMAT = @"yyyy-MM-dd\THH:mm:ss";
private const string MESSAGE_NAME_PROPERTY = "m";
private const string MESSAGE_DATA_PROPERTY = "d";
/// <summary>
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
/// </summary>
/// <typeparam name="T"></typeparam>
public static void CacheType<T>()
where T : new()
{
CacheType(typeof(T));
}
/// <summary>
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
/// </summary>
public static void CacheType(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type));
JsonConvert.DeserializeObject(serialized, type);
}
/// <summary>
/// Gets the token as a DateTime value.
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
[PublicAPI]
public static DateTime ParseDateTime(JToken token)
{
if (token == null)
throw new ArgumentNullException("token");
#if SIMPLSHARP
return DateTime.ParseExact((string)token, DATE_FORMAT, CultureInfo.CurrentCulture);
#else
return (DateTime)token;
#endif
}
/// <summary>
/// Gets the token as a DateTime value.
/// </summary>
/// <param name="token"></param>
/// <param name="output"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParseDateTime(JToken token, out DateTime output)
{
if (token == null)
throw new ArgumentNullException("token");
output = default(DateTime);
try
{
output = ParseDateTime(token);
return true;
}
catch (InvalidCastException)
{
return false;
}
}
/// <summary>
/// Pretty-prints the JSON document.
/// </summary>
/// <param name="json"></param>
[PublicAPI]
public static void Print(string json)
{
if (json == null)
throw new ArgumentNullException("json");
string formatted = Format(json);
IcdConsole.PrintLine(formatted);
}
/// <summary>
/// Serializes the given item and pretty-prints to JSON.
/// </summary>
/// <param name="value"></param>
[PublicAPI]
public static void Print(object value)
{
string formatted = Format(value);
IcdConsole.PrintLine(formatted);
}
/// <summary>
/// Serializes the given item and formats the JSON into a human-readable form.
/// </summary>
@@ -234,6 +139,22 @@ namespace ICD.Common.Utils.Json
}
}
/// <summary>
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
/// E.g.
/// { a = 1 }
/// Becomes
/// { m = "Test", d = { a = 1 } }
/// </summary>
/// <param name="value"></param>
/// <param name="messageName"></param>
/// <returns></returns>
[PublicAPI]
public static string SerializeMessage(object value, string messageName)
{
return SerializeMessage(w => new JsonSerializer().Serialize(w, value), messageName);
}
/// <summary>
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
/// E.g.
@@ -317,44 +238,5 @@ namespace ICD.Common.Utils.Json
},
json);
}
/// <summary>
/// Deserializes the given token based on the known type.
/// </summary>
/// <param name="type"></param>
/// <param name="token"></param>
/// <returns></returns>
public static object Deserialize(Type type, JToken token)
{
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
return Deserialize(type, token, new JsonSerializer());
}
/// <summary>
/// Deserializes the given token based on the known type.
/// </summary>
/// <param name="type"></param>
/// <param name="token"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public static object Deserialize(Type type, JToken token, JsonSerializer serializer)
{
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
if (serializer == null)
throw new ArgumentNullException("serializer");
using (JTokenReader jsonReader = new JTokenReader(token))
return serializer.Deserialize(jsonReader, type);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Properties;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Json
{
/// <summary>
/// Simply reads/writes values from/to JSON as their string representation.
/// </summary>
[PublicAPI]
public sealed class ToStringJsonConverter : JsonConverter
{
private static readonly Dictionary<Type, MethodInfo> s_ParseMethods;
public override bool CanRead { get { return true; } }
/// <summary>
/// Static constructor.
/// </summary>
static ToStringJsonConverter()
{
s_ParseMethods = new Dictionary<Type, MethodInfo>();
}
#region Methods
public override bool CanConvert(Type objectType)
{
return true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
MethodInfo parse = GetParseMethod(objectType);
if (parse == null)
throw new ArgumentException(
string.Format("{0} does not have a 'static {0} Parse(string)' method.", objectType.Name),
"objectType");
try
{
return parse.Invoke(null, new[] { reader.Value });
}
catch (TargetInvocationException e)
{
throw e.InnerException;
}
}
#endregion
[CanBeNull]
private static MethodInfo GetParseMethod(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
MethodInfo output;
if (!s_ParseMethods.TryGetValue(type, out output))
{
output = type
#if SIMPLSHARP
.GetCType()
.GetMethod("Parse",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
CType.DefaultBinder,
new CType[] {typeof(string)},
new ParameterModifier[] {});
#else
.GetTypeInfo()
.GetMethod("Parse",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
Type.DefaultBinder,
new[] {typeof(string)},
new ParameterModifier[] {});
#endif
s_ParseMethods.Add(type, output);
}
return output;
}
}
}

View File

@@ -78,6 +78,24 @@ namespace ICD.Common.Utils
return outputStart + slope * (value - inputStart);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static decimal MapRange(decimal inputStart, decimal inputEnd, decimal outputStart, decimal outputEnd, decimal value)
{
if (inputStart.Equals(inputEnd))
throw new DivideByZeroException();
decimal slope = (outputEnd - outputStart) / (inputEnd - inputStart);
return outputStart + slope * (value - inputStart);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
@@ -191,5 +209,18 @@ namespace ICD.Common.Utils
return nearest.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y);
}
/// <summary>
/// Calculates the modulus of the given number.
/// </summary>
/// <param name="number"></param>
/// <param name="mod"></param>
/// <returns></returns>
/// <remarks>method name can't be "Mod", due to S+ compatability issues</remarks>
public static int Modulus(int number, int mod)
{
int remainder = number % mod;
return remainder < 0 ? remainder + mod : remainder;
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
@@ -17,7 +19,15 @@ namespace ICD.Common.Utils
/// Gets the path to the root directory of the processor.
/// </summary>
[PublicAPI]
public static string RootPath { get { return IcdDirectory.GetDirectoryRoot("\\"); } }
public static string RootPath {
get
{
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
return IcdDirectory.GetApplicationRootDirectory();
return IcdDirectory.GetDirectoryRoot(IcdPath.DirectorySeparatorChar.ToString());
}
}
/// <summary>
/// Gets the path to the program directory
@@ -35,11 +45,11 @@ namespace ICD.Common.Utils
get
{
#if SIMPLSHARP
return Join(RootPath, "USER");
return Join(RootPath, "User");
#elif LINUX
return Join(RootPath, "opt", "ICD.Connect");
#else
return Join(RootPath, "ProgramData", "ICD.Connect");
return Join(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "ICD.Connect");
#endif
}
}
@@ -49,12 +59,60 @@ namespace ICD.Common.Utils
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramConfigPath
public static string ProgramConfigPath { get { return Join(RootConfigPath, ProgramConfigDirectory); } }
/// <summary>
/// Returns the name of the program config directory.
/// </summary>
[PublicAPI]
public static string ProgramConfigDirectory
{
get
{
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
return Join(RootConfigPath, directoryName);
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
return "ProgramConfig";
default:
throw new ArgumentOutOfRangeException();
}
}
}
/// <summary>
/// Returns the absolute path to the program data directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramDataPath { get { return Join(RootConfigPath, ProgramDataDirectory); } }
/// <summary>
/// Returns the name of the program data directory.
/// This directory contains runtime program data that should be retained through deployments.
/// </summary>
public static string ProgramDataDirectory
{
get
{
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
return string.Format("Program{0:D2}Data", ProgramUtils.ProgramNumber);
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
return "ProgramData";
default:
throw new ArgumentOutOfRangeException();
}
}
}
@@ -62,7 +120,10 @@ namespace ICD.Common.Utils
/// Returns the absolute path to the common configuration directory.
/// </summary>
[PublicAPI]
public static string CommonConfigPath { get { return Join(RootConfigPath, "CommonConfig"); } }
public static string CommonConfigPath { get { return Join(RootConfigPath, CommonConfigDirectory); } }
[PublicAPI]
public static string CommonConfigDirectory { get { return "CommonConfig"; }}
/// <summary>
/// Returns the absolute path to the common config library directory.
@@ -76,6 +137,37 @@ namespace ICD.Common.Utils
[PublicAPI]
public static string ProgramLibPath { get { return Join(ProgramConfigPath, "Lib"); } }
/// <summary>
/// Returns the absolute path to the logs directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramLogsPath
{
get
{
string directoryName;
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
directoryName = string.Format("Program{0:D2}Logs", ProgramUtils.ProgramNumber);
break;
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
directoryName = "ProgramLogs";
break;
default:
throw new ArgumentOutOfRangeException();
}
return Join(RootConfigPath, directoryName);
}
}
#endregion
#region Methods

View File

@@ -9,14 +9,21 @@ namespace ICD.Common.Utils
{
public static partial class ProcessorUtils
{
private const string MODEL_NAME_REGEX = @"^(\S*)";
private const string MODEL_VERSION_REGEX = @" [[]v(\S*)";
private const string VER_REGEX =
@"(?'model'\S+) (?'type'\S+) (?'lang'\S+) \[v(?'version'\d+.\d+.\d+.\d+) \((?'date'\S+ \d+ \d+)\), #(?'serial'[A-F0-9]+)\] @E-(?'mac'[a-z0-9]+)";
private const string UPTIME_COMMAND = "uptime";
private const string PROGUPTIME_COMMAND_ROOT = "proguptime:{0}";
private const string UPTIME_REGEX = @".*(?'uptime'(?'days'\d+) days (?'hours'\d{2}):(?'minutes'\d{2}):(?'seconds'\d{2})\.(?'milliseconds'\d+))";
private const string RAMFREE_COMMAND = "ramfree";
private const string RAMFREE_DIGITS_REGEX = @"^(\d*)";
private static string s_VersionResult;
private static DateTime? s_SystemUptimeStartTime;
private static DateTime? s_ProgramUptimeStartTime;
#region Properties
/// <summary>
@@ -48,11 +55,15 @@ namespace ICD.Common.Utils
{
get
{
Regex regex = new Regex(MODEL_NAME_REGEX);
Match match = regex.Match(VersionResult);
string versionResult = VersionResult;
if (!String.IsNullOrEmpty(versionResult))
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(versionResult);
if (match.Success)
return match.Groups[1].Value;
if (match.Success)
return match.Groups["model"].Value;
}
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model name from \"{0}\"", VersionResult);
@@ -68,11 +79,15 @@ namespace ICD.Common.Utils
{
get
{
Regex regex = new Regex(MODEL_VERSION_REGEX);
Match match = regex.Match(VersionResult);
string versionResult = VersionResult;
if (!String.IsNullOrEmpty(versionResult))
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return new Version(match.Groups[1].Value);
if (match.Success)
return new Version(match.Groups["version"].Value);
}
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version from \"{0}\"", VersionResult);
@@ -80,6 +95,51 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Gets the date that the firmware was updated.
/// </summary>
[PublicAPI]
public static string ModelVersionDate
{
get
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return match.Groups["date"].Value;
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version date from \"{0}\"", VersionResult);
return string.Empty;
}
}
/// <summary>
/// Gets the serial number of the processor
/// </summary>
[PublicAPI]
public static string ProcessorSerialNumber
{
get
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (!match.Success)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get serial number from \"{0}\"", VersionResult);
return string.Empty;
}
int decValue = int.Parse(match.Groups["serial"].Value, System.Globalization.NumberStyles.HexNumber);
return decValue.ToString();
}
}
/// <summary>
/// Gets the ram usage in the range 0 - 1.
/// </summary>
@@ -170,6 +230,60 @@ namespace ICD.Common.Utils
IcdConsole.SendControlSystemCommand("reboot", ref consoleResult);
}
/// <summary>
/// Gets the uptime for the system
/// </summary>
/// <returns></returns>
[PublicAPI]
public static TimeSpan GetSystemUptime()
{
if (s_SystemUptimeStartTime == null)
{
string uptime = GetSystemUptimeFeedback();
Match match = Regex.Match(uptime, UPTIME_REGEX);
if (!match.Success)
return default(TimeSpan);
int days = int.Parse(match.Groups["days"].Value);
int hours = int.Parse(match.Groups["hours"].Value);
int minutes = int.Parse(match.Groups["minutes"].Value);
int seconds = int.Parse(match.Groups["seconds"].Value);
int milliseconds = int.Parse(match.Groups["milliseconds"].Value);
TimeSpan span = new TimeSpan(days, hours, minutes, seconds, milliseconds);
s_SystemUptimeStartTime = IcdEnvironment.GetLocalTime() - span;
}
return IcdEnvironment.GetLocalTime() - s_SystemUptimeStartTime.Value;
}
/// <summary>
/// Gets the uptime of the current program.
/// </summary>
/// <returns></returns>
[PublicAPI]
public static TimeSpan GetProgramUptime()
{
if (s_ProgramUptimeStartTime == null)
{
string uptime = GetProgramUptimeFeedback((int)ProgramUtils.ProgramNumber);
Match match = Regex.Match(uptime, UPTIME_REGEX);
if (!match.Success)
return default(TimeSpan);
int days = int.Parse(match.Groups["days"].Value);
int hours = int.Parse(match.Groups["hours"].Value);
int minutes = int.Parse(match.Groups["minutes"].Value);
int seconds = int.Parse(match.Groups["seconds"].Value);
int milliseconds = int.Parse(match.Groups["milliseconds"].Value);
TimeSpan span = new TimeSpan(days, hours, minutes, seconds, milliseconds);
s_ProgramUptimeStartTime = IcdEnvironment.GetLocalTime() - span;
}
return IcdEnvironment.GetLocalTime() - s_ProgramUptimeStartTime.Value;
}
#endregion
/// <summary>
@@ -187,6 +301,30 @@ namespace ICD.Common.Utils
}
return ramfree;
}
private static string GetSystemUptimeFeedback()
{
string uptime = null;
if (!IcdConsole.SendControlSystemCommand(UPTIME_COMMAND, ref uptime))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(ProcessorUtils).Name, UPTIME_COMMAND);
}
return uptime;
}
private static string GetProgramUptimeFeedback(int programSlot)
{
string uptime = null;
if (!IcdConsole.SendControlSystemCommand(string.Format(PROGUPTIME_COMMAND_ROOT, programSlot), ref uptime))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(ProcessorUtils).Name, UPTIME_COMMAND);
}
return uptime;
}
}
}

View File

@@ -27,6 +27,32 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Gets the date that the firmware was updated.
/// </summary>
[PublicAPI]
public static string ModelVersionDate
{
get
{
// TODO
return null;
}
}
/// <summary>
/// Gets the serial number of the processor
/// </summary>
[PublicAPI]
public static string ProcessorSerialNumber
{
get
{
// TODO
return null;
}
}
/// <summary>
/// Gets the ram usage in the range 0 - 1.
/// </summary>
@@ -109,6 +135,27 @@ namespace ICD.Common.Utils
throw new NotSupportedException();
}
/// <summary>
/// Gets the uptime for the system
/// </summary>
/// <returns></returns>
[PublicAPI]
public static TimeSpan GetSystemUptime()
{
return TimeSpan.FromMilliseconds(Environment.TickCount);
}
/// <summary>
/// Gets the uptime
/// </summary>
/// <returns></returns>
[PublicAPI]
public static TimeSpan GetProgramUptime()
{
var current = System.Diagnostics.Process.GetCurrentProcess();
return IcdEnvironment.GetLocalTime() - current.StartTime;
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using ICD.Common.Utils.Services;
using ICD.Common.Utils.IO;
using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using Crestron.SimplSharp;
@@ -86,6 +87,16 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Returns the date and time the program was installed.
/// </summary>
/// <returns></returns>
[PublicAPI]
public static DateTime ProgramInstallDate
{
get { return IcdFile.GetCreationTime(PathUtils.Join(PathUtils.ProgramPath, ProgramFile)); }
}
/// <summary>
/// Parses the prog comments and pulls program information.
/// </summary>

View File

@@ -55,6 +55,15 @@ namespace ICD.Common.Utils
return Assembly.GetEntryAssembly().GetName().Name;
}
}
}
/// <summary>
/// Gets the date and time the program was installed.
/// </summary>
[PublicAPI]
public static DateTime ProgramInstallDate
{
get { return IcdFile.GetCreationTime(PathUtils.Join(PathUtils.ProgramPath, ProgramFile)); }
}
}
}
#endif

View File

@@ -33,6 +33,10 @@ namespace ICD.Common.Utils
name = name.Substring(0, proLength).PadRight(26);
break;
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
// No console
return;
case IcdEnvironment.eRuntimeEnvironment.Standard:
name += ' ';
break;

View File

@@ -3,5 +3,5 @@ using System.Reflection;
[assembly: AssemblyTitle("ICD.Common.Utils")]
[assembly: AssemblyCompany("ICD Systems")]
[assembly: AssemblyProduct("ICD.Common.Utils")]
[assembly: AssemblyCopyright("Copyright © ICD Systems 2018")]
[assembly: AssemblyVersion("7.0.0.0")]
[assembly: AssemblyCopyright("Copyright © ICD Systems 2019")]
[assembly: AssemblyVersion("9.9.0.0")]

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
@@ -31,6 +32,24 @@ namespace ICD.Common.Utils
.Select(node => GetClique(map, visited, node));
}
/// <summary>
/// Gets the clique containing the given node.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="node"></param>
/// <param name="getAdjacent"></param>
/// <returns></returns>
public static IEnumerable<T> GetClique<T>(T node, Func<T, IEnumerable<T>> getAdjacent)
{
if (node == null)
throw new ArgumentNullException("node");
if (getAdjacent == null)
throw new ArgumentNullException("getAdjacent");
return BreadthFirstSearch(node, getAdjacent);
}
/// <summary>
/// Gets the clique containing the given node.
/// </summary>
@@ -97,23 +116,23 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Returns true if there is a path from the given root to the given child node.
/// Returns true if there is a path from the given root to the given destination node.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="root"></param>
/// <param name="child"></param>
/// <param name="destination"></param>
/// <param name="getChildren"></param>
/// <returns></returns>
public static bool BreadthFirstSearch<T>(T root, T child, Func<T, IEnumerable<T>> getChildren)
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
{
if (getChildren == null)
throw new ArgumentNullException("getChildren");
return BreadthFirstSearchPath(root, child, getChildren) != null;
return BreadthFirstSearch(root, destination, getChildren, EqualityComparer<T>.Default);
}
/// <summary>
/// Returns true if there is a path from the given root to the given child node.
/// Returns true if there is a path from the given root to the given destination node.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="root"></param>
@@ -148,7 +167,7 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Returns all of the nodes in the tree via breadth-first search.
/// Returns all of the nodes in the graph via breadth-first search.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="root"></param>
@@ -156,16 +175,20 @@ namespace ICD.Common.Utils
/// <returns></returns>
private static IEnumerable<T> BreadthFirstSearchIterator<T>(T root, Func<T, IEnumerable<T>> getChildren)
{
IcdHashSet<T> visited = new IcdHashSet<T> {root};
Queue<T> process = new Queue<T>();
process.Enqueue(root);
while (process.Count > 0)
T current;
while (process.Dequeue(out current))
{
T current = process.Dequeue();
yield return current;
foreach (T child in getChildren(current))
foreach (T child in getChildren(current).Where(c => !visited.Contains(c)))
{
visited.Add(child);
process.Enqueue(child);
}
}
}
@@ -214,10 +237,9 @@ namespace ICD.Common.Utils
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
while (queue.Count > 0)
T current;
while (queue.Dequeue(out current))
{
T current = queue.Dequeue();
foreach (T node in getChildren(current))
{
if (nodeParents.ContainsKey(node))

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
#if SIMPLSHARP
@@ -146,6 +147,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
[CanBeNull]
public static object GetDefaultValue(Type type)
{
if (type == null)
@@ -167,6 +169,7 @@ namespace ICD.Common.Utils
/// <param name="firstArgument"></param>
/// <param name="method"></param>
/// <returns></returns>
[NotNull]
public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method)
{
return
@@ -182,6 +185,7 @@ namespace ICD.Common.Utils
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
/// <returns></returns>
[NotNull]
public static T CreateInstance<T>(Type type)
{
if (type == null)
@@ -195,6 +199,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[NotNull]
public static T CreateInstance<T>(params object[] parameters)
{
if (parameters == null)
@@ -207,6 +212,7 @@ namespace ICD.Common.Utils
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
/// <returns></returns>
[NotNull]
public static object CreateInstance(Type type, params object[] parameters)
{
if (type == null)
@@ -214,11 +220,15 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
ConstructorInfo constructor = GetConstructor(type, parameters);
try
{
if (parameters.Length == 0)
return Activator.CreateInstance(type);
ConstructorInfo constructor = GetConstructor(type, parameters);
return constructor.Invoke(parameters);
}
catch (TypeLoadException e)
@@ -237,6 +247,7 @@ namespace ICD.Common.Utils
/// <param name="type"></param>
/// <param name="parameters"></param>
/// <returns></returns>
[NotNull]
public static ConstructorInfo GetConstructor(Type type, params object[] parameters)
{
if (type == null)
@@ -245,13 +256,18 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
return
type
ConstructorInfo info;
if(!type
#if SIMPLSHARP
.GetCType()
.GetCType()
#endif
.GetConstructors()
.First(c => MatchesConstructorParameters(c, parameters));
.GetConstructors()
.Where(c => MatchesConstructorParameters(c, parameters))
.TryFirst(out info))
throw new ArgumentException("Couldn't find a constructor matching the given parameters.");
return info;
}
/// <summary>
@@ -259,6 +275,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
[NotNull]
public static Assembly LoadAssemblyFromPath(string path)
{
if (path == null)
@@ -299,6 +316,7 @@ namespace ICD.Common.Utils
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
[CanBeNull]
public static object ChangeType(object value, Type type)
{
if (type == null)
@@ -325,8 +343,9 @@ namespace ICD.Common.Utils
if (valueType.IsIntegerNumeric())
return Enum.ToObject(type, value);
if (value is string)
return Enum.Parse(type, value as string, false);
string valueAsString = value as string;
if (valueAsString != null)
return Enum.Parse(type, valueAsString, false);
}
return Convert.ChangeType(value, type, null);
@@ -340,13 +359,62 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Subscribes to the event on the given instance using the handler and callback method.
/// Subscribes to the event on the given instance using the event handler.
/// </summary>
/// <param name="instance">The instance with the event. Null for static types.</param>
/// <param name="eventInfo">The EventInfo for the event.</param>
/// <param name="handler">The instance with the callback MethodInfo. Null for static types.</param>
/// <param name="callback">The MethodInfo for the callback method.</param>
/// <param name="eventHandler">The EventHandler for the callback.</param>
/// <returns></returns>
[NotNull]
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, Action<object> eventHandler)
{
if (eventInfo == null)
throw new ArgumentNullException("eventInfo");
if (eventHandler == null)
throw new ArgumentNullException("eventHandler");
object handler = eventHandler.Target;
// ReSharper disable InvokeAsExtensionMethod
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
// ReSharper restore InvokeAsExtensionMethod
return SubscribeEvent(instance, eventInfo, handler, callback);
}
/// <summary>
/// Subscribes to the event on the given instance using the event handler.
/// </summary>
/// <param name="instance">The instance with the event. Null for static types.</param>
/// <param name="eventInfo">The EventInfo for the event.</param>
/// <param name="eventHandler">The EventHandler for the callback.</param>
/// <returns></returns>
[NotNull]
public static Delegate SubscribeEvent<T>(object instance, EventInfo eventInfo, Action<object, T> eventHandler)
{
if (eventInfo == null)
throw new ArgumentNullException("eventInfo");
if (eventHandler == null)
throw new ArgumentNullException("eventHandler");
object handler = eventHandler.Target;
// ReSharper disable InvokeAsExtensionMethod
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
// ReSharper restore InvokeAsExtensionMethod
return SubscribeEvent(instance, eventInfo, handler, callback);
}
/// <summary>
/// Subscribes to the event on the given instance using the handler and eventHandler method.
/// </summary>
/// <param name="instance">The instance with the event. Null for static types.</param>
/// <param name="eventInfo">The EventInfo for the event.</param>
/// <param name="handler">The instance with the eventHandler MethodInfo. Null for static types.</param>
/// <param name="callback">The MethodInfo for the eventHandler method.</param>
/// <returns></returns>
[NotNull]
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, object handler, MethodInfo callback)
{
if (eventInfo == null)

View File

@@ -1,4 +1,7 @@
using System.Text.RegularExpressions;
using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace ICD.Common.Utils
{
@@ -30,5 +33,83 @@ namespace ICD.Common.Utils
match = Regex.Match(input, pattern, options);
return match.Success;
}
/// <summary>
/// Uses the pattern to replace the specified group with the provided replacement string.
/// </summary>
/// <param name="input"></param>
/// <param name="pattern"></param>
/// <param name="groupName"></param>
/// <param name="replacement"></param>
/// <returns></returns>
public static string ReplaceGroup(string input, string pattern, string groupName, string replacement)
{
return ReplaceGroup(input, pattern, groupName, replacement, RegexOptions.None);
}
/// <summary>
/// Uses the pattern to replace the specified group with the provided replacement string.
/// </summary>
/// <param name="input"></param>
/// <param name="pattern"></param>
/// <param name="groupName"></param>
/// <param name="replacement"></param>
/// <returns></returns>
public static string ReplaceGroup(string input, string pattern, string groupName, Func<Match, string> replacement)
{
return ReplaceGroup(input, pattern, groupName, replacement, RegexOptions.None);
}
/// <summary>
/// Uses the pattern to replace the specified group with the provided replacement string.
/// </summary>
/// <param name="input"></param>
/// <param name="pattern"></param>
/// <param name="groupName"></param>
/// <param name="replacement"></param>
/// <param name="options"></param>
/// <returns></returns>
public static string ReplaceGroup(string input, string pattern, string groupName, string replacement, RegexOptions options)
{
return ReplaceGroup(input, pattern, groupName, match => replacement, options);
}
/// <summary>
/// Uses the pattern to replace the specified group with the provided replacement string.
/// </summary>
/// <param name="input"></param>
/// <param name="pattern"></param>
/// <param name="groupName"></param>
/// <param name="replacement"></param>
/// <param name="options"></param>
/// <returns></returns>
public static string ReplaceGroup(string input, string pattern, string groupName, Func<Match, string> replacement, RegexOptions options)
{
MatchEvaluator evaluator =
m =>
{
string replacementString = replacement(m);
Group group = m.Groups[groupName];
StringBuilder sb = new StringBuilder();
int previousCaptureEnd = 0;
foreach (Capture capture in group.Captures.Cast<Capture>())
{
int currentCaptureEnd = capture.Index + capture.Length - m.Index;
int currentCaptureLength = capture.Index - m.Index - previousCaptureEnd;
sb.Append(m.Value.Substring(previousCaptureEnd, currentCaptureLength));
sb.Append(replacementString);
previousCaptureEnd = currentCaptureEnd;
}
sb.Append(m.Value.Substring(previousCaptureEnd));
return sb.ToString();
};
return Regex.Replace(input, pattern, evaluator, options);
}
}
}

View File

@@ -12,8 +12,7 @@ namespace ICD.Common.Utils
{
private readonly object m_Instance;
private readonly List<string> m_PropertyOrder;
private readonly Dictionary<string, string> m_PropertyValues;
private readonly List<KeyValuePair<string, string>> m_PropertyOrder;
/// <summary>
/// Constructor.
@@ -23,8 +22,7 @@ namespace ICD.Common.Utils
{
m_Instance = instance;
m_PropertyOrder = new List<string>();
m_PropertyValues = new Dictionary<string, string>();
m_PropertyOrder = new List<KeyValuePair<string, string>>();
}
/// <summary>
@@ -32,14 +30,10 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AppendProperty(string name, object value)
public ReprBuilder AppendProperty(string name, object value)
{
m_PropertyOrder.Remove(name);
m_PropertyOrder.Add(name);
string valueString = GetValueStringRepresentation(value);
m_PropertyValues[name] = valueString;
return AppendPropertyRaw(name, valueString);
}
/// <summary>
@@ -47,12 +41,10 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AppendPropertyRaw(string name, string value)
public ReprBuilder AppendPropertyRaw(string name, string value)
{
m_PropertyOrder.Remove(name);
m_PropertyOrder.Add(name);
m_PropertyValues[name] = value;
m_PropertyOrder.Add(new KeyValuePair<string, string>(name, value));
return this;
}
/// <summary>
@@ -62,7 +54,7 @@ namespace ICD.Common.Utils
public override string ToString()
{
if (m_Instance == null)
return GetValueStringRepresentation(m_Instance);
return GetValueStringRepresentation(null);
StringBuilder builder = new StringBuilder();
@@ -71,12 +63,11 @@ namespace ICD.Common.Utils
for (int index = 0; index < m_PropertyOrder.Count; index++)
{
string property = m_PropertyOrder[index];
builder.Append(property);
builder.Append('=');
KeyValuePair<string, string> pair = m_PropertyOrder[index];
string valueString = m_PropertyValues[property];
builder.Append(valueString);
builder.Append(pair.Key);
builder.Append('=');
builder.Append(pair.Value);
if (index < m_PropertyOrder.Count - 1)
builder.Append(", ");

View File

@@ -0,0 +1,23 @@
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
/// <summary>
/// Static class containing useful utilities for use in S+ programs
/// </summary>
[PublicAPI("S+")]
public static class SPlusUtils
{
/// <summary>
/// Convert two ushort's to an int
/// </summary>
/// <param name="lowWord">ushort for the least significant 16 bits</param>
/// <param name="highWord">ushort for the most significant 1 bits</param>
/// <returns></returns>
[PublicAPI("S+")]
public static int ConvertToInt(ushort lowWord, ushort highWord)
{
return (highWord << 16) + lowWord;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Text;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Services.Logging
@@ -21,11 +20,6 @@ namespace ICD.Common.Utils.Services.Logging
[PublicAPI]
public DateTime Timestamp { get { return m_Timestamp; } }
/// <summary>
/// Gets the log time in local time.
/// </summary>
public DateTime LocalTimestamp { get { return Timestamp.ToLocalTime(); } }
/// <summary>
/// Get/Set for severity level.
/// </summary>
@@ -56,24 +50,6 @@ namespace ICD.Common.Utils.Services.Logging
#region Methods
/// <summary>
/// Return the text format to send to Fusion
/// </summary>
/// <returns>text format for fusion, including timestamp, severity, and message</returns>
[PublicAPI]
public string GetFusionLogText()
{
StringBuilder s = new StringBuilder();
s.Append(Timestamp.ToString("yyyyMMddHHmmss"));
s.Append("||");
s.Append((int)Severity);
s.Append("||");
s.Append(Message);
return s.ToString();
}
/// <summary>
/// Implementing default equality.
/// </summary>

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
@@ -228,18 +227,7 @@ namespace ICD.Common.Utils.Services
if (tService == null)
throw new ArgumentNullException("tService");
try
{
m_ServicesSection.Enter();
object service;
m_Services.TryGetValue(tService, out service);
return service;
}
finally
{
m_ServicesSection.Leave();
}
return m_ServicesSection.Execute(() => m_Services.GetDefault(tService));
}
/// <summary>
@@ -265,7 +253,7 @@ namespace ICD.Common.Utils.Services
/// <returns></returns>
private IEnumerable<object> GetServicesInstance()
{
return m_ServicesSection.Execute(() => m_Services.Values.ToList());
return m_ServicesSection.Execute(() => m_Services.Values.ToArray(m_Services.Count));
}
/// <summary>

View File

@@ -32,8 +32,8 @@ namespace ICD.Common.Utils.Sqlite
/// <param name="path"></param>
public static void CreateFile(string path)
{
IcdFileStream fs = IcdFile.Create(path);
fs.Close();
using (IcdFileStream fs = IcdFile.Create(path))
fs.Close();
}
/// <summary>

View File

@@ -34,5 +34,30 @@ namespace ICD.Common.Utils.Sqlite
{
return m_Reader.Read();
}
public int GetInt32(int ordinal)
{
return m_Reader.GetInt32(ordinal);
}
public bool GetBoolean(int ordinal)
{
return m_Reader.GetBoolean(ordinal);
}
public string GetString(int ordinal)
{
return m_Reader.GetString(ordinal);
}
public int GetOrdinal(string name)
{
return m_Reader.GetOrdinal(name);
}
public void Close()
{
m_Reader.Close();
}
}
}

View File

@@ -6,22 +6,27 @@ using Microsoft.Data.Sqlite;
namespace ICD.Common.Utils.Sqlite
{
public sealed class IcdSqliteParameterCollection
{
private readonly SqliteParameterCollection m_Parameters;
public sealed class IcdSqliteParameterCollection
{
private readonly SqliteParameterCollection m_Parameters;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="commandParameters"></param>
public IcdSqliteParameterCollection(SqliteParameterCollection commandParameters)
public IcdSqliteParameterCollection(SqliteParameterCollection commandParameters)
{
m_Parameters = commandParameters;
}
public IcdSqliteParameter Add(string name, eDbType type)
{
{
return new IcdSqliteParameter(m_Parameters.Add(name, type.ToParamType()));
}
}
}
public void AddWithValue(string parameterName, object value)
{
m_Parameters.AddWithValue(parameterName, value);
}
}
}

View File

@@ -17,7 +17,6 @@ namespace ICD.Common.Utils
private const char INTERSECT = '+';
private readonly List<string[]> m_Rows;
private readonly SafeCriticalSection m_RowsSection;
private readonly string[] m_Columns;
/// <summary>
@@ -39,7 +38,6 @@ namespace ICD.Common.Utils
public TableBuilder(params string[] columns)
{
m_Rows = new List<string[]>();
m_RowsSection = new SafeCriticalSection();
m_Columns = columns;
}
@@ -49,9 +47,10 @@ namespace ICD.Common.Utils
/// Clears all of the rows.
/// </summary>
[PublicAPI]
public void ClearRows()
public TableBuilder ClearRows()
{
m_RowsSection.Execute(() => m_Rows.Clear());
m_Rows.Clear();
return this;
}
/// <summary>
@@ -59,11 +58,11 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params object[] row)
public TableBuilder AddRow(params object[] row)
{
string[] stringRow = row.Select(o => string.Format("{0}", o))
.ToArray();
AddRow(stringRow);
return AddRow(stringRow);
}
/// <summary>
@@ -71,31 +70,33 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params string[] row)
public TableBuilder AddRow(params string[] row)
{
if (row != null && row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
m_RowsSection.Execute(() => m_Rows.Add(row));
m_Rows.Add(row);
return this;
}
/// <summary>
/// Adds an empty row to the builder.
/// </summary>
[PublicAPI]
public void AddEmptyRow()
public TableBuilder AddEmptyRow()
{
AddRow(new string[m_Columns.Length]);
return AddRow(new string[m_Columns.Length]);
}
[PublicAPI]
public void AddSeparator()
public TableBuilder AddSeparator()
{
AddRow(null);
return AddRow(null);
}
[PublicAPI]
public void AddHeader(params string[] row)
public TableBuilder AddHeader(params string[] row)
{
if (row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
@@ -103,6 +104,8 @@ namespace ICD.Common.Utils
AddSeparator();
AddRow(row);
AddSeparator();
return this;
}
/// <summary>
@@ -112,30 +115,21 @@ namespace ICD.Common.Utils
{
StringBuilder sb = new StringBuilder();
m_RowsSection.Enter();
int[] columnWidths = GetColumnWidths();
try
AppendRow(sb, m_Columns, columnWidths);
AppendSeparator(sb, columnWidths);
foreach (string[] row in m_Rows)
{
int[] columnWidths = GetColumnWidths();
AppendRow(sb, m_Columns, columnWidths);
AppendSeparator(sb, columnWidths);
foreach (string[] row in m_Rows)
{
if (row == null)
AppendSeparator(sb, columnWidths);
else
AppendRow(sb, row, columnWidths);
}
AppendSeparator(sb, columnWidths);
}
finally
{
m_RowsSection.Leave();
if (row == null)
AppendSeparator(sb, columnWidths);
else
AppendRow(sb, row, columnWidths);
}
AppendSeparator(sb, columnWidths);
return sb.ToString();
}

View File

@@ -20,7 +20,7 @@ namespace ICD.Common.Utils.Timers
private readonly Timer m_Timer;
private int m_RepeatPeriod;
#endif
private readonly Action m_Callback;
private Action m_Callback;
/// <summary>
/// Returns true if this instance has been disposed.
@@ -67,8 +67,8 @@ namespace ICD.Common.Utils.Timers
/// <returns></returns>
public static SafeTimer Stopped(Action callback)
{
// Some arbitrarily large number that shouldn't timeout before we call stop.
SafeTimer output = new SafeTimer(callback, 100 * 1000, 100 * 1000);
//No due time or repeat period on a stopped timer
SafeTimer output = new SafeTimer(callback, -1, -1);
output.Stop();
return output;
}
@@ -85,10 +85,12 @@ namespace ICD.Common.Utils.Timers
if (IsDisposed)
return;
IsDisposed = true;
Stop();
m_Timer.Dispose();
IsDisposed = true;
m_Callback = null;
}
/// <summary>
@@ -158,7 +160,8 @@ namespace ICD.Common.Utils.Timers
// Essentially the meat of this class. There's some weirdness with the garbage collector where
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
// despite being stopped/disposed.
if (m_Timer == null
if (IsDisposed ||
m_Timer == null
#if SIMPLSHARP
|| m_Timer.Disposed
#endif

View File

@@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Text;
namespace ICD.Common.Utils
{
public sealed class UriQueryBuilder
{
private readonly Dictionary<string, string> m_Parameters;
public UriQueryBuilder()
{
m_Parameters = new Dictionary<string, string>();
}
public UriQueryBuilder Append(string key, string value)
{
m_Parameters.Add(key, value);
return this;
}
public override string ToString()
{
StringBuilder builder = new StringBuilder("?");
bool first = true;
foreach (KeyValuePair<string, string> kvp in m_Parameters)
{
if (!first)
builder.Append('&');
first = false;
builder.Append(kvp.Key);
builder.Append('=');
builder.Append(kvp.Value);
}
return builder.ToString();
}
}
}

View File

@@ -1,9 +1,17 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils
{
public static class UriUtils
{
private static readonly Dictionary<string, ushort> s_SchemeToPort =
new Dictionary<string, ushort>(StringComparer.OrdinalIgnoreCase)
{
{Uri.UriSchemeHttp, 80},
{Uri.UriSchemeHttps, 443}
};
/// <summary>
/// Attempts to parse the given URI string into a System.Uri instance.
/// </summary>
@@ -27,5 +35,16 @@ namespace ICD.Common.Utils
return false;
}
}
/// <summary>
/// Gets the port number for the given URI scheme.
/// </summary>
/// <param name="scheme"></param>
/// <param name="port"></param>
/// <returns></returns>
public static bool TryGetPortForScheme(string scheme, out ushort port)
{
return s_SchemeToPort.TryGetValue(scheme, out port);
}
}
}

View File

@@ -48,7 +48,9 @@ namespace ICD.Common.Utils.Xml
if (writer == null)
throw new ArgumentNullException("writer");
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
{
writer.WriteElementString(elementName, null);
return;

View File

@@ -1,80 +0,0 @@
using System;
namespace ICD.Common.Utils.Xml
{
/// <summary>
/// IcdXmlAttribute represents an attribute="value" pair from xml.
/// </summary>
public struct IcdXmlAttribute : IEquatable<IcdXmlAttribute>
{
private readonly string m_Name;
private readonly string m_Value;
public string Name { get { return m_Name; } }
public string Value { get { return m_Value; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public IcdXmlAttribute(string name, string value)
{
m_Name = name;
m_Value = value;
}
/// <summary>
/// Implementing default equality.
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator ==(IcdXmlAttribute a1, IcdXmlAttribute a2)
{
return a1.Equals(a2);
}
/// <summary>
/// Implementing default inequality.
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator !=(IcdXmlAttribute a1, IcdXmlAttribute a2)
{
return !a1.Equals(a2);
}
public bool Equals(IcdXmlAttribute other)
{
return m_Name == other.m_Name &&
m_Value == other.m_Value;
}
/// <summary>
/// Returns true if this instance is equal to the given object.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public override bool Equals(object other)
{
return other is IcdXmlAttribute && Equals((IcdXmlAttribute)other);
}
/// <summary>
/// Gets the hashcode for this instance.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (m_Name == null ? 0 : m_Name.GetHashCode());
hash = hash * 23 + (m_Value == null ? 0 : m_Value.GetHashCode());
return hash;
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
@@ -72,7 +73,12 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("type");
using (IcdXmlReader reader = new IcdXmlReader(xml))
return DeserializeObject(type, reader);
{
if (reader.ReadToNextElement())
return DeserializeObject(type, reader);
throw new FormatException("Expected element in XML");
}
}
/// <summary>
@@ -108,6 +114,64 @@ namespace ICD.Common.Utils.Xml
return converter.ReadXml(reader);
}
/// <summary>
/// Deserializes the child elements as items in an array.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader"></param>
/// <returns></returns>
public static IEnumerable<T> DeserializeArray<T>(IcdXmlReader reader)
{
if (reader == null)
throw new ArgumentNullException("reader");
return DeserializeArray(typeof(T), reader).Cast<T>();
}
/// <summary>
/// Deserializes the child elements as items in an array.
/// </summary>
/// <param name="type"></param>
/// <param name="reader"></param>
/// <returns></returns>
public static IEnumerable<object> DeserializeArray(Type type, IcdXmlReader reader)
{
if (type == null)
throw new ArgumentNullException("type");
if (reader == null)
throw new ArgumentNullException("reader");
if (reader.NodeType != XmlNodeType.Element)
throw new FormatException("Expected start element for array");
string arrayName = reader.Name;
// Read into the first element
do
{
reader.Read();
} while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.EndElement);
// Empty array
if (reader.NodeType == XmlNodeType.EndElement)
yield break;
// Read the items
IXmlConverter converter = XmlConverterAttribute.GetConverterForType(type);
while (reader.NodeType != XmlNodeType.EndElement)
{
yield return converter.ReadXml(reader);
reader.SkipInsignificantWhitespace();
}
if (reader.NodeType != XmlNodeType.EndElement || reader.Name != arrayName)
throw new FormatException("Expected end element for array");
// Read out of the array end element
reader.Read();
}
public static string ToString(int value)
{
return XmlConvert.ToString(value);
@@ -208,37 +272,127 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("type");
if (type == typeof(bool))
return bool.Parse(value);
return ToBool(value);
if (type == typeof(byte))
return byte.Parse(value);
return ToByte(value);
if (type == typeof(decimal))
return decimal.Parse(value);
return ToDecimal(value);
if (type == typeof(char))
return value.Single();
return ToChar(value);
if (type == typeof(double))
return double.Parse(value);
return ToDouble(value);
if (type == typeof(Guid))
return new Guid(value);
return ToGuid(value);
if (type == typeof(float))
return float.Parse(value);
return ToSingle(value);
if (type == typeof(int))
return int.Parse((value));
return ToInt32(value);
if (type == typeof(long))
return long.Parse(value);
return ToInt64(value);
if (type == typeof(sbyte))
return sbyte.Parse(value);
return ToSByte(value);
if (type == typeof(short))
return short.Parse(value);
return ToInt16(value);
if (type == typeof(TimeSpan))
return TimeSpan.Parse(value);
return ToTimeSpan(value);
if (type == typeof(uint))
return uint.Parse(value);
return ToUInt32(value);
if (type == typeof(ulong))
return ulong.Parse(value);
return ToUInt64(value);
if (type == typeof(ushort))
return ushort.Parse(value);
return ToUInt16(value);
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
}
public static bool ToBool(string data)
{
return XmlConvert.ToBoolean(data);
}
public static byte ToByte(string data)
{
return XmlConvert.ToByte(data);
}
public static char ToChar(string data)
{
return XmlConvert.ToChar(data);
}
public static DateTime ToDateTime(string data, string format)
{
return XmlConvert.ToDateTime(data, format);
}
public static DateTime ToDateTime(string data, string[] formats)
{
return XmlConvert.ToDateTime(data, formats);
}
public static DateTime ToDateTime(string data, XmlDateTimeSerializationMode dateTimeOption)
{
return XmlConvert.ToDateTime(data, dateTimeOption);
}
public static decimal ToDecimal(string data)
{
return XmlConvert.ToDecimal(data);
}
public static double ToDouble(string data)
{
return XmlConvert.ToDouble(data);
}
public static Guid ToGuid(string data)
{
return XmlConvert.ToGuid(data);
}
public static short ToInt16(string data)
{
return XmlConvert.ToInt16(data);
}
public static int ToInt32(string data)
{
return XmlConvert.ToInt32(data);
}
public static long ToInt64(string data)
{
return XmlConvert.ToInt64(data);
}
public static sbyte ToSByte(string data)
{
return XmlConvert.ToSByte(data);
}
public static float ToSingle(string data)
{
return XmlConvert.ToSingle(data);
}
public static TimeSpan ToTimeSpan(string data)
{
return XmlConvert.ToTimeSpan(data);
}
public static ushort ToUInt16(string data)
{
return XmlConvert.ToUInt16(data);
}
public static uint ToUInt32(string data)
{
return XmlConvert.ToUInt32(data);
}
public static ulong ToUInt64(string data)
{
return XmlConvert.ToUInt64(data);
}
}
}

Some files were not shown because too many files have changed in this diff Show More