mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-27 03:15:00 +00:00
Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
644388edad | ||
|
|
cbb05c8b79 | ||
|
|
066c9f93a7 | ||
|
|
9aa7459b0f | ||
|
|
f8a813c97b | ||
|
|
be6a6de65a | ||
|
|
ffe3e67241 | ||
|
|
141d911eb0 | ||
|
|
d6abf3fdf6 | ||
|
|
46a1ea09b6 | ||
|
|
2dc705d335 | ||
|
|
0700a357dd | ||
|
|
5fb7636ed4 | ||
|
|
196c2a535a | ||
|
|
db50ada952 | ||
|
|
087b04fd62 | ||
|
|
ea73351d39 | ||
|
|
ca1fae29b0 | ||
|
|
1916c2b750 | ||
|
|
3af2544e70 | ||
|
|
20e8aa93f2 | ||
|
|
3937902f38 | ||
|
|
021d5781a3 | ||
|
|
b429e4bc53 | ||
|
|
4a203e2449 | ||
|
|
d41203b856 | ||
|
|
2f21379e52 | ||
|
|
f60de4321b | ||
|
|
bd2ea606ae | ||
|
|
1f20c07e94 | ||
|
|
1be588b86a | ||
|
|
488df297fc | ||
|
|
80a4d94358 | ||
|
|
6a40f3ce18 | ||
|
|
d564a0a423 | ||
|
|
a9a544c433 | ||
|
|
2e0837f5c8 | ||
|
|
77be0ec477 | ||
|
|
524cdc3e31 | ||
|
|
1d6e8d55ca | ||
|
|
3ba5f11587 | ||
|
|
fb7a6e27b8 | ||
|
|
fffc8e4a60 | ||
|
|
1d7ada87c5 | ||
|
|
3a4438ec1e | ||
|
|
21ce86de0f | ||
|
|
3cb29452a2 | ||
|
|
114a5e4ec7 | ||
|
|
a9d411dcfd | ||
|
|
e708ef9603 | ||
|
|
aae4fb6185 | ||
|
|
8401ab1852 | ||
|
|
27760f2282 | ||
|
|
80a0ca26c5 | ||
|
|
b9ec2f3222 | ||
|
|
a6ad52d492 | ||
|
|
64e11db0bc | ||
|
|
d01e9345d5 | ||
|
|
466dc6deb5 | ||
|
|
ad47c890a8 | ||
|
|
108317212c | ||
|
|
4a411e8990 | ||
|
|
4cd28a8a12 | ||
|
|
470c35cab7 | ||
|
|
a372d97868 | ||
|
|
f208ec521b | ||
|
|
347cf70b6c | ||
|
|
1076795fae | ||
|
|
7d059bc605 | ||
|
|
dd270adf9e | ||
|
|
efb5e014ec | ||
|
|
083280cc64 | ||
|
|
e222ce424b | ||
|
|
ad7176506d | ||
|
|
e4e3e9b91a | ||
|
|
1721116908 | ||
|
|
d8489d31b6 | ||
|
|
a8552ea0e3 | ||
|
|
e700650735 | ||
|
|
ed9c017856 | ||
|
|
0ee1b440ee | ||
|
|
4184f85826 | ||
|
|
42cc8c2cfc | ||
|
|
6b37db3530 | ||
|
|
ad8fa216a5 | ||
|
|
ef415bb20f | ||
|
|
fe614ae8ad | ||
|
|
2d4bc57ed8 | ||
|
|
c048c4fc65 | ||
|
|
2e2eebd95f | ||
|
|
e21830a7d5 | ||
|
|
f53607018c | ||
|
|
e0176741d2 | ||
|
|
742b7e99aa | ||
|
|
cf0c71d39b | ||
|
|
376f9c0837 | ||
|
|
8b1c53ebe1 | ||
|
|
2e0b0da87f | ||
|
|
8311fe5c9d | ||
|
|
fb41d76a9c | ||
|
|
8f107aa209 | ||
|
|
2024dc0171 | ||
|
|
923866dbdf | ||
|
|
a14b4a5803 | ||
|
|
fac2610b83 | ||
|
|
0ef0286a9f | ||
|
|
d084553600 | ||
|
|
2b14a6b65c | ||
|
|
043a50669a | ||
|
|
b58220d3c7 | ||
|
|
03de74a494 | ||
|
|
6eacc21e45 | ||
|
|
db14eb1dde | ||
|
|
24e665de84 | ||
|
|
7e8618d3e5 | ||
|
|
e44a18b111 | ||
|
|
5cec0e10f1 | ||
|
|
e01bc9ede6 | ||
|
|
9e6c7ca6b3 | ||
|
|
2a1d58f2ae | ||
|
|
51dcb41cdf | ||
|
|
11cff4f5bb | ||
|
|
7c29fb72d9 | ||
|
|
fc234af43a | ||
|
|
5afc676fbe | ||
|
|
ba8c1d98a1 | ||
|
|
63af420710 | ||
|
|
25109163fb | ||
|
|
91f64a4fb1 | ||
|
|
78a3373592 | ||
|
|
14cce04c12 | ||
|
|
d3d1dae2e1 | ||
|
|
e9063682ef | ||
|
|
699c734389 | ||
|
|
548220ba0e | ||
|
|
692da3253f | ||
|
|
85ab631ef5 | ||
|
|
23a068d0c9 | ||
|
|
b015c3a3d3 | ||
|
|
566884167f | ||
|
|
015ffb2c35 | ||
|
|
6540ab5177 | ||
|
|
e01e41c449 | ||
|
|
8a260e0475 | ||
|
|
381355beb9 | ||
|
|
2a25c3d733 | ||
|
|
6b8fc19eb3 | ||
|
|
c3d73e1091 | ||
|
|
1f5625218f | ||
|
|
588badbf58 | ||
|
|
e0fae0b112 | ||
|
|
315bd703c7 | ||
|
|
32aae27a7f | ||
|
|
db15ea24d9 | ||
|
|
667c1cdd21 | ||
|
|
df30585917 | ||
|
|
09603b0537 | ||
|
|
d41aa6d111 | ||
|
|
9867eae704 | ||
|
|
e1693bc738 | ||
|
|
2c87d8e988 | ||
|
|
deff0d5408 | ||
|
|
0ccf80c613 | ||
|
|
a3e548290f | ||
|
|
12ee533cbb | ||
|
|
2ae8fa9c2d | ||
|
|
0bfd6c4f48 | ||
|
|
c2b980a691 | ||
|
|
2ff7073385 | ||
|
|
80e6fe33c7 |
81
CHANGELOG.md
81
CHANGELOG.md
@@ -6,6 +6,87 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [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.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
|
||||
- Significant hashset optimizations
|
||||
- Deprecated NVRAM in favor of USER directory
|
||||
|
||||
## [6.0.0] - 2018-10-18
|
||||
### Added
|
||||
- CsvWriter for creating CSV files + Settings
|
||||
- AppendText method for IcdFile
|
||||
- IcdStreamWriter, a wrapper for a StreamWriter
|
||||
- New XML conversion framework for performance improvements
|
||||
|
||||
### Changed
|
||||
- XmlUtils is now using the improved XML conversion framework
|
||||
- Better implementation of DictionaryExtensions.ToInverse
|
||||
|
||||
## [5.0.0] - 2018-09-14
|
||||
### Added
|
||||
- Stopwatch profiling methods
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,6 @@ namespace ICD.Common.Utils.Tests.Collections
|
||||
[TestFixture]
|
||||
public sealed class IcdHashSetTest
|
||||
{
|
||||
[Test, UsedImplicitly]
|
||||
public void NullSetTest()
|
||||
{
|
||||
Assert.AreEqual(0, IcdHashSet<int>.NullSet.Count);
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
public void CountTest()
|
||||
{
|
||||
|
||||
@@ -301,5 +301,29 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.AreEqual(20, ordered[1]);
|
||||
Assert.AreEqual(30, ordered[2]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToInverseTest()
|
||||
{
|
||||
Dictionary<int, string> forward = new Dictionary<int, string>
|
||||
{
|
||||
{ 1, "testA" },
|
||||
{ 2, "testA" },
|
||||
{ 3, "testB" },
|
||||
{ 4, "testB" }
|
||||
};
|
||||
|
||||
Dictionary<string, List<int>> backwards = new Dictionary<string, List<int>>
|
||||
{
|
||||
{"testA", new List<int> {1, 2}},
|
||||
{"testB", new List<int> {3, 4}}
|
||||
};
|
||||
|
||||
Dictionary<string, List<int>> inverse = forward.ToInverse();
|
||||
|
||||
bool equal = inverse.DictionaryEqual(backwards, (v1, v2) => v1.ScrambledEquals(v2));
|
||||
|
||||
Assert.IsTrue(equal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +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]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SplitStringDelimiterTest()
|
||||
{
|
||||
string[] split = "1234567890".Split("23").ToArray();
|
||||
[TestCase("12345", " 12 3 4 \t 5\n")]
|
||||
public void RemoveWhitespaceTest(string expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.RemoveWhitespace());
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, split.Length);
|
||||
Assert.AreEqual("14567890", string.Join("", split));
|
||||
}
|
||||
[TestCase("1234567890", "12345", "67890")]
|
||||
[TestCase("foobarfoobar", "bar", "foofoo")]
|
||||
public void RemoveStringTest(string value, string other, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, value.Remove(other));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SplitStringDelimitersTest()
|
||||
{
|
||||
string[] split = "1234567890".Split(new[] { "23", "67" }).ToArray();
|
||||
[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));
|
||||
}
|
||||
|
||||
Assert.AreEqual(3, split.Length);
|
||||
Assert.AreEqual("145890", string.Join("", split));
|
||||
}
|
||||
|
||||
[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(true, "27652")]
|
||||
[TestCase(false, "a27652")]
|
||||
public void IsNumericTest(bool expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.IsNumeric());
|
||||
}
|
||||
}
|
||||
[TestCase(true, "27652")]
|
||||
[TestCase(false, "a27652")]
|
||||
public void IsNumericTest(bool expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.IsNumeric());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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?>")]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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
|
||||
@@ -141,32 +140,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";
|
||||
|
||||
@@ -178,11 +178,13 @@ namespace ICD.Common.Utils.Tests
|
||||
[Test]
|
||||
public void BreadthFirstSearchManyDestinationsTest()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 1 }, null));
|
||||
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchManyDestinations(1, null, Graph));
|
||||
Assert.IsEmpty(RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 5 }, Graph));
|
||||
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] { 1 }, null));
|
||||
Assert.Throws<ArgumentNullException>(() => RecursionUtils.BreadthFirstSearchPathManyDestinations(1, null, Graph));
|
||||
Assert.AreEqual(0, RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] { 5 }, Graph).Count());
|
||||
|
||||
Dictionary<int, IEnumerable<int>> paths = RecursionUtils.BreadthFirstSearchManyDestinations(1, new[] { 21, 22, 31, 43, 62 }, WideGraph);
|
||||
Dictionary<int, IEnumerable<int>> paths =
|
||||
RecursionUtils.BreadthFirstSearchPathManyDestinations(1, new[] {21, 22, 31, 43, 62}, WideGraph)
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
//Make sure all paths were found
|
||||
Assert.IsTrue(paths.Keys.Contains(21));
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
38
ICD.Common.Utils.Tests/RegexUtilsTest.cs
Normal file
38
ICD.Common.Utils.Tests/RegexUtilsTest.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,10 +61,10 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual("[-3 - 5]", StringUtils.RangeFormat(-3, 5));
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
public void UppercaseFirstTest()
|
||||
[TestCase("foobar", "Foobar")]
|
||||
public void UppercaseFirstTest(string value, string expected)
|
||||
{
|
||||
Assert.AreEqual("Foobar", StringUtils.UppercaseFirst("foobar"));
|
||||
Assert.AreEqual(expected, StringUtils.UppercaseFirst(value));
|
||||
}
|
||||
|
||||
[TestCase("test", "Test")]
|
||||
@@ -74,16 +74,24 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual(expected, StringUtils.ToTitleCase(input));
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
public void ToIpIdStringTest()
|
||||
[TestCase((byte)0x67, "0x67")]
|
||||
public void ToIpIdStringTest(byte ipid, string expected)
|
||||
{
|
||||
Assert.AreEqual("0x67", StringUtils.ToIpIdString(0x67));
|
||||
Assert.AreEqual(expected, StringUtils.ToIpIdString(ipid));
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
public void FromIpIdStringTest()
|
||||
[TestCase("0x67", (byte)0x67)]
|
||||
public void FromIpIdStringTest(string value, byte expected)
|
||||
{
|
||||
Assert.AreEqual(0x67, StringUtils.FromIpIdString("0x67"));
|
||||
Assert.AreEqual(expected, StringUtils.FromIpIdString(value));
|
||||
}
|
||||
|
||||
[TestCase("0x67", true, (byte)0x67)]
|
||||
public void TryFromIpIdStringTest(string value, bool expected, byte expectedOutput)
|
||||
{
|
||||
byte output;
|
||||
Assert.AreEqual(expected, StringUtils.TryFromIpIdString(value, out output));
|
||||
Assert.AreEqual(expectedOutput, output);
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,7 @@ namespace ICD.Common.Utils.Tests.Xml
|
||||
{
|
||||
paths.Add(args.Path);
|
||||
nodes.Add(args.Outer);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -176,13 +177,6 @@ namespace ICD.Common.Utils.Tests.Xml
|
||||
}
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
public void IsValidXmlTest()
|
||||
{
|
||||
Assert.IsFalse(XmlUtils.IsValidXml(@"<Foo></Bar>"));
|
||||
Assert.IsTrue(XmlUtils.IsValidXml(EXAMPLE_XML));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FormatTest()
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace ICD.Common.Utils
|
||||
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;
|
||||
|
||||
@@ -38,26 +37,12 @@ namespace ICD.Common.Utils
|
||||
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>
|
||||
@@ -70,6 +55,8 @@ namespace ICD.Common.Utils
|
||||
if (s_CachedAssemblies.Contains(assembly))
|
||||
return true;
|
||||
|
||||
s_CachedAssemblies.Add(assembly);
|
||||
|
||||
#if SIMPLSHARP
|
||||
CType[] types;
|
||||
#else
|
||||
@@ -114,7 +101,6 @@ namespace ICD.Common.Utils
|
||||
foreach (var type in types)
|
||||
CacheType(type);
|
||||
|
||||
s_CachedAssemblies.Add(assembly);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -133,44 +119,23 @@ namespace ICD.Common.Utils
|
||||
|
||||
if (s_CachedTypes.Contains(type))
|
||||
return;
|
||||
s_CachedTypes.Add(type);
|
||||
|
||||
MethodInfo[] methods;
|
||||
s_CachedTypes.Add(type);
|
||||
|
||||
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
|
||||
@@ -183,7 +148,6 @@ namespace ICD.Common.Utils
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetClassAttributes<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return s_AttributeToTypeCache.Select(kvp => kvp.Key)
|
||||
.OfType<T>();
|
||||
@@ -197,7 +161,6 @@ namespace ICD.Common.Utils
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
public static T GetClassAttribute<T>(Type type)
|
||||
where T : Attribute
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
@@ -212,7 +175,6 @@ 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");
|
||||
@@ -253,29 +215,27 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the cached method attributes of the given type.
|
||||
/// Returns the properties on the given instance with property attributes of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="instance"></param>
|
||||
/// <param name="inherit"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetMethodAttributes<T>()
|
||||
where T : Attribute
|
||||
public static IEnumerable<PropertyInfo> GetProperties<T>(object instance, bool inherit)
|
||||
{
|
||||
return s_AttributeToMethodCache.Select(p => p.Key)
|
||||
.OfType<T>()
|
||||
.ToArray();
|
||||
}
|
||||
if (instance == null)
|
||||
throw new ArgumentNullException("instance");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cached method for the given attribute.
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodInfo GetMethod(Attribute attribute)
|
||||
{
|
||||
if (attribute == null)
|
||||
throw new ArgumentNullException("attribute");
|
||||
|
||||
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
|
||||
|
||||
228
ICD.Common.Utils/Attributes/RangeAttribute.cs
Normal file
228
ICD.Common.Utils/Attributes/RangeAttribute.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
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,
|
||||
AllowMultiple = false,
|
||||
Inherited = true)]
|
||||
public sealed class RangeAttribute : AbstractIcdAttribute
|
||||
{
|
||||
#region Properties
|
||||
|
||||
[NotNull]
|
||||
public object Min { get; private set; }
|
||||
|
||||
[NotNull]
|
||||
public object Max { get; private set; }
|
||||
|
||||
[NotNull]
|
||||
private Type Type { get { return Min.GetType(); } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public RangeAttribute(ushort min, ushort max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(short min, short max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(uint min, uint max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(int min, int max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(ulong min, ulong max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(long min, long max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(float min, float max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(double min, double max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(byte min, byte max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(sbyte min, sbyte max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public RangeAttribute(decimal min, decimal max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given value is within the range of Min to Max.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInRange(object value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (value.GetType() != Type)
|
||||
throw new ArgumentException("the type of value does not match the type of min / max");
|
||||
|
||||
if (value is ushort)
|
||||
{
|
||||
var castMin = (ushort)Min;
|
||||
var castMax = (ushort)Max;
|
||||
var castVal = (ushort)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is short)
|
||||
{
|
||||
var castMin = (short)Min;
|
||||
var castMax = (short)Max;
|
||||
var castVal = (short)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is uint)
|
||||
{
|
||||
var castMin = (uint)Min;
|
||||
var castMax = (uint)Max;
|
||||
var castVal = (uint)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is int)
|
||||
{
|
||||
var castMin = (int)Min;
|
||||
var castMax = (int)Max;
|
||||
var castVal = (int)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is ulong)
|
||||
{
|
||||
var castMin = (ulong)Min;
|
||||
var castMax = (ulong)Max;
|
||||
var castVal = (ulong)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is long)
|
||||
{
|
||||
var castMin = (long)Min;
|
||||
var castMax = (long)Max;
|
||||
var castVal = (long)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is float)
|
||||
{
|
||||
var castMin = (float)Min;
|
||||
var castMax = (float)Max;
|
||||
var castVal = (float)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is double)
|
||||
{
|
||||
var castMin = (double)Min;
|
||||
var castMax = (double)Max;
|
||||
var castVal = (double)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is decimal)
|
||||
{
|
||||
var castMin = (decimal)Min;
|
||||
var castMax = (decimal)Max;
|
||||
var castVal = (decimal)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is byte)
|
||||
{
|
||||
var castMin = (byte)Min;
|
||||
var castMax = (byte)Max;
|
||||
var castVal = (byte)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
if (value is sbyte)
|
||||
{
|
||||
var castMin = (sbyte)Min;
|
||||
var castMax = (sbyte)Max;
|
||||
var castVal = (sbyte)value;
|
||||
return (castVal >= castMin && castVal <= castMax);
|
||||
}
|
||||
|
||||
throw new ArgumentException("the type of value is not a numeric type.");
|
||||
}
|
||||
|
||||
public ushort RemapRangeToUShort(double value)
|
||||
{
|
||||
return (ushort)MathUtils.MapRange((double)Min, (double)Max, ushort.MinValue, ushort.MaxValue, value);
|
||||
}
|
||||
|
||||
public ushort RemapRangeToUShort(float value)
|
||||
{
|
||||
return (ushort)MathUtils.MapRange((float)Min, (float)Max, ushort.MinValue, ushort.MaxValue, value);
|
||||
}
|
||||
|
||||
public ushort RemapRangeToUShort(int value)
|
||||
{
|
||||
return (ushort)MathUtils.MapRange((int)Min, (int)Max, ushort.MinValue, ushort.MaxValue, value);
|
||||
}
|
||||
|
||||
public ushort RemapRangeToUShort(ushort value)
|
||||
{
|
||||
return MathUtils.MapRange((ushort)Min, (ushort)Max, ushort.MinValue, ushort.MaxValue, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -16,12 +16,6 @@ namespace ICD.Common.Utils.Collections
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new, empty hashset.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static IcdHashSet<T> NullSet { get { return new IcdHashSet<T>(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
@@ -98,11 +92,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public IcdHashSet<T> Union(IEnumerable<T> set)
|
||||
{
|
||||
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
|
||||
|
||||
if (set == null)
|
||||
return unionSet;
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> unionSet = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
unionSet.AddRange(set);
|
||||
|
||||
return unionSet;
|
||||
@@ -116,10 +109,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public IcdHashSet<T> Subtract(IEnumerable<T> set)
|
||||
{
|
||||
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
|
||||
|
||||
if (set == null)
|
||||
return subtractSet;
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> subtractSet = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
|
||||
foreach (T item in set)
|
||||
subtractSet.Remove(item);
|
||||
@@ -133,15 +126,12 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <param name="set"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public IcdHashSet<T> Intersection(IcdHashSet<T> set)
|
||||
public IcdHashSet<T> Intersection(IEnumerable<T> set)
|
||||
{
|
||||
IcdHashSet<T> intersectionSet = NullSet;
|
||||
|
||||
if (set == null)
|
||||
return intersectionSet;
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
foreach (T item in this.Where(set.Contains))
|
||||
intersectionSet.Add(item);
|
||||
IcdHashSet<T> intersectionSet = new IcdHashSet<T>(m_Dict.Comparer);
|
||||
|
||||
foreach (T item in set.Where(Contains))
|
||||
intersectionSet.Add(item);
|
||||
@@ -155,11 +145,22 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <param name="set"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public IcdHashSet<T> NonIntersection(IcdHashSet<T> set)
|
||||
public IcdHashSet<T> NonIntersection(IEnumerable<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return Subtract(set).Union(setToCompare.Subtract(this));
|
||||
IcdHashSet<T> output = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
|
||||
foreach (T item in set)
|
||||
{
|
||||
if (output.Contains(item))
|
||||
output.Remove(item);
|
||||
else
|
||||
output.Add(item);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -170,9 +171,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool IsSubsetOf(IcdHashSet<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return this.All(setToCompare.Contains);
|
||||
return Count <= set.Count && this.All(set.Contains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -183,9 +185,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool IsProperSubsetOf(IcdHashSet<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this);
|
||||
return Count < set.Count && IsSubsetOf(set);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -196,9 +199,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool IsSupersetOf(IcdHashSet<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return setToCompare.IsSubsetOf(this);
|
||||
return set.IsSubsetOf(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,9 +213,10 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool IsProperSupersetOf(IcdHashSet<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this);
|
||||
return set.IsProperSubsetOf(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,14 +227,15 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool SetEquals(IcdHashSet<T> set)
|
||||
{
|
||||
IcdHashSet<T> setToCompare = set ?? NullSet;
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return IsSupersetOf(setToCompare) && setToCompare.IsSupersetOf(this);
|
||||
return Count == set.Count && set.All(Contains);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection<T> Members
|
||||
#region ICollection<T>
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item to the collection. Returns false if the item already exists.
|
||||
@@ -238,9 +244,9 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <returns></returns>
|
||||
public bool Add(T item)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (item == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
if (m_Dict.ContainsKey(item))
|
||||
@@ -288,6 +294,11 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <returns></returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (item == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
return m_Dict.ContainsKey(item);
|
||||
}
|
||||
|
||||
@@ -309,12 +320,17 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (item == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
return m_Dict.Remove(item);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
#region IEnumerable<T>
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
|
||||
@@ -80,6 +80,20 @@ namespace ICD.Common.Utils.Collections
|
||||
m_Dictionary = new Dictionary<TKey, TValue>(equalityComparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="dictionary"></param>
|
||||
public IcdOrderedDictionary(IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
|
||||
: this()
|
||||
{
|
||||
if (dictionary == null)
|
||||
throw new ArgumentNullException("dictionary");
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
|
||||
Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
|
||||
@@ -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
|
||||
|
||||
137
ICD.Common.Utils/Csv/CsvWriter.cs
Normal file
137
ICD.Common.Utils/Csv/CsvWriter.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.IO;
|
||||
|
||||
namespace ICD.Common.Utils.Csv
|
||||
{
|
||||
public sealed class CsvWriter : IDisposable
|
||||
{
|
||||
private const string QUOTATION_MARK = "\"";
|
||||
private const string DOUBLE_QUOTE_MARK = "\"\"";
|
||||
|
||||
private readonly IcdTextWriter m_Writer;
|
||||
|
||||
private readonly string m_Seperator;
|
||||
private readonly string m_LineTerminator;
|
||||
private readonly bool m_AlwaysEscape;
|
||||
|
||||
private bool m_NewLine;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public CsvWriter(IcdTextWriter writer, bool spaceAfterComma, bool alwaysEscape, string newline, params string[] header)
|
||||
{
|
||||
m_NewLine = true;
|
||||
m_Writer = writer;
|
||||
m_Seperator = spaceAfterComma ? ", " : ",";
|
||||
m_AlwaysEscape = alwaysEscape;
|
||||
m_LineTerminator = newline;
|
||||
|
||||
if(header.Any())
|
||||
AppendRow(header);
|
||||
}
|
||||
|
||||
~CsvWriter()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls ToString() for each item and adds the row to the builder.
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AppendRow(params object[] row)
|
||||
{
|
||||
foreach (object value in row)
|
||||
AppendValue(value);
|
||||
AppendNewline();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the row to the builder.
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AppendRow(params string[] row)
|
||||
{
|
||||
foreach (string value in row)
|
||||
AppendValue(value);
|
||||
AppendNewline();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls ToString() on the item and adds it to the builder.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[PublicAPI]
|
||||
public void AppendValue(object value)
|
||||
{
|
||||
AppendValue(string.Format("{0}", value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a value to the builder.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[PublicAPI]
|
||||
public void AppendValue(string value)
|
||||
{
|
||||
value = value ?? string.Empty;
|
||||
|
||||
if (!m_NewLine)
|
||||
m_Writer.WrappedTextWriter.Write(m_Seperator);
|
||||
|
||||
if (m_AlwaysEscape || value.Contains(","))
|
||||
{
|
||||
value = value.Replace(QUOTATION_MARK, DOUBLE_QUOTE_MARK);
|
||||
|
||||
// Append the value, surrounded by quotes
|
||||
m_Writer.WrappedTextWriter.Write(QUOTATION_MARK);
|
||||
m_Writer.WrappedTextWriter.Write(value);
|
||||
m_Writer.WrappedTextWriter.Write(QUOTATION_MARK);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Writer.WrappedTextWriter.Write(value);
|
||||
}
|
||||
|
||||
m_NewLine = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a New Line To the Builder
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void AppendNewline()
|
||||
{
|
||||
m_Writer.WrappedTextWriter.Write(m_LineTerminator);
|
||||
|
||||
m_NewLine = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_Writer.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new CsvWriter with the properties given in the CsvWriterSettings.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="settings"></param>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static CsvWriter Create(IcdTextWriter writer, CsvWriterSettings settings, params string[] header)
|
||||
{
|
||||
return new CsvWriter(writer,
|
||||
settings.InsertSpaceAfterComma,
|
||||
settings.AlwaysEscapeEveryValue,
|
||||
settings.NewLineSequence,
|
||||
header);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
ICD.Common.Utils/Csv/CsvWriterSettings.cs
Normal file
46
ICD.Common.Utils/Csv/CsvWriterSettings.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Csv
|
||||
{
|
||||
public sealed class CsvWriterSettings
|
||||
{
|
||||
private bool m_InsertSpaceAfterComma = true;
|
||||
private bool m_AlwaysEscapeEveryValue = true;
|
||||
private string m_NewLineSequence = IcdEnvironment.NewLine;
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets whether to insert a space between elements, after the comma
|
||||
/// Defaults to true.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool InsertSpaceAfterComma
|
||||
{
|
||||
get { return m_InsertSpaceAfterComma; }
|
||||
set { m_InsertSpaceAfterComma = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets whether to always escape the values.
|
||||
/// If true, values are recorded surrounded by quotes, regardless of if they contain a comma or not. Quotes are escaped.
|
||||
/// If false, values are recorded as the value without quotes, unless escaping is required.
|
||||
/// Defaults to true.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool AlwaysEscapeEveryValue
|
||||
{
|
||||
get { return m_AlwaysEscapeEveryValue; }
|
||||
set { m_AlwaysEscapeEveryValue = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the newline character or characters to deliniate records.
|
||||
/// Defaults to System.NewLine.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string NewLineSequence
|
||||
{
|
||||
get { return m_NewLineSequence; }
|
||||
set { m_NewLineSequence = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
91
ICD.Common.Utils/Email/EmailClient.cs
Normal file
91
ICD.Common.Utils/Email/EmailClient.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
using System.Net.Mail;
|
||||
#endif
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Email
|
||||
{
|
||||
public sealed class EmailClient
|
||||
{
|
||||
private readonly EmailStringCollection m_To;
|
||||
private readonly EmailStringCollection m_Cc;
|
||||
private readonly EmailStringCollection m_Bcc;
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Host { get; set; }
|
||||
public ushort Port { get; set; }
|
||||
public bool Secure { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string From { get; set; }
|
||||
public EmailStringCollection To { get { return m_To; } }
|
||||
public EmailStringCollection Cc { get { return m_Cc; } }
|
||||
public EmailStringCollection Bcc { get { return m_Bcc; } }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public EmailClient()
|
||||
{
|
||||
m_To = new EmailStringCollection();
|
||||
m_Cc = new EmailStringCollection();
|
||||
m_Bcc = new EmailStringCollection();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sends the email.
|
||||
/// </summary>
|
||||
/// <param name="subject"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns>Error codes.</returns>
|
||||
[PublicAPI]
|
||||
public eMailErrorCode Send(string subject, string message)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
var response = CrestronMailFunctions.SendMail(Host, Port, Secure, Username, Password, From, m_To.ToString(), "",
|
||||
m_Cc.ToString(), m_Bcc.ToString(), subject, message,
|
||||
CrestronMailFunctions.eMailPriority.Normal, 0, "");
|
||||
|
||||
return MailErrorCodeUtils.FromSimplMailCode(response);
|
||||
#else
|
||||
try
|
||||
{
|
||||
MailMessage mailMessage = new MailMessage
|
||||
{
|
||||
From = new MailAddress(From),
|
||||
To = {m_To.ToString()},
|
||||
CC = {m_Cc.ToString()},
|
||||
Bcc = {m_Bcc.ToString()},
|
||||
Subject = subject,
|
||||
Body = message
|
||||
};
|
||||
|
||||
SmtpClient client = new SmtpClient
|
||||
{
|
||||
Port = Port,
|
||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
||||
UseDefaultCredentials = false,
|
||||
Host = Host
|
||||
};
|
||||
|
||||
client.Send(mailMessage);
|
||||
}
|
||||
catch (SmtpException ex)
|
||||
{
|
||||
return MailErrorCodeUtils.FromNetStandardMailCode(ex.StatusCode);
|
||||
}
|
||||
|
||||
return eMailErrorCode.Ok;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
134
ICD.Common.Utils/Email/EmailStringCollection.cs
Normal file
134
ICD.Common.Utils/Email/EmailStringCollection.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Email
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores addresses/paths and provides them in a ; delimited string.
|
||||
/// </summary>
|
||||
public sealed class EmailStringCollection : ICollection<string>
|
||||
{
|
||||
private const char DELIMITER = ';';
|
||||
|
||||
private readonly List<string> m_Items;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of items.
|
||||
/// </summary>
|
||||
public int Count { get { return m_Items.Count; } }
|
||||
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public EmailStringCollection()
|
||||
{
|
||||
m_Items = new List<string>();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Adds the item to the collection.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public bool Add(string item)
|
||||
{
|
||||
if (m_Items.Contains(item))
|
||||
return false;
|
||||
|
||||
m_Items.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the item from the collection.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public bool Remove(string item)
|
||||
{
|
||||
if (!m_Items.Contains(item))
|
||||
return false;
|
||||
|
||||
m_Items.Remove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all items.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_Items.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the collection contains the item.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public bool Contains(string item)
|
||||
{
|
||||
return m_Items.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items as a ; delimited string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join(DELIMITER.ToString(), m_Items.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collection
|
||||
|
||||
void ICollection<string>.Add(string item)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds multiple email addresses, seperated by ;
|
||||
/// </summary>
|
||||
/// <param name="items"></param>
|
||||
public void AddMany(string items)
|
||||
{
|
||||
items = items.RemoveWhitespace();
|
||||
string [] splitItems = items.Split(DELIMITER);
|
||||
foreach (string item in splitItems)
|
||||
Add(item);
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex)
|
||||
{
|
||||
m_Items.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enumerable
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
{
|
||||
return m_Items.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
233
ICD.Common.Utils/Email/eMailErrorCode.cs
Normal file
233
ICD.Common.Utils/Email/eMailErrorCode.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using System;
|
||||
#if STANDARD
|
||||
using System.Net.Mail;
|
||||
#endif
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils.Email
|
||||
{
|
||||
public enum eMailErrorCode
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// The transaction could not occur. You receive this error when the specified SMTP
|
||||
// host cannot be found.
|
||||
GeneralFailure = -1,
|
||||
//
|
||||
// Summary:
|
||||
// A system status or system Help reply.
|
||||
SystemStatus = 211,
|
||||
//
|
||||
// Summary:
|
||||
// A Help message was returned by the service.
|
||||
HelpMessage = 214,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service is ready.
|
||||
ServiceReady = 220,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service is closing the transmission channel.
|
||||
ServiceClosingTransmissionChannel = 221,
|
||||
//
|
||||
// Summary:
|
||||
// The email was successfully sent to the SMTP service.
|
||||
Ok = 250,
|
||||
//
|
||||
// Summary:
|
||||
// The user mailbox is not located on the receiving server; the server forwards
|
||||
// the e-mail.
|
||||
UserNotLocalWillForward = 251,
|
||||
//
|
||||
// Summary:
|
||||
// The specified user is not local, but the receiving SMTP service accepted the
|
||||
// message and attempted to deliver it. This status code is defined in RFC 1123,
|
||||
// which is available at http://www.ietf.org/.
|
||||
CannotVerifyUserWillAttemptDelivery = 252,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service is ready to receive the e-mail content.
|
||||
StartMailInput = 354,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service is not available; the server is closing the transmission channel.
|
||||
ServiceNotAvailable = 421,
|
||||
//
|
||||
// Summary:
|
||||
// The destination mailbox is in use.
|
||||
MailboxBusy = 450,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service cannot complete the request. This error can occur if the client's
|
||||
// IP address cannot be resolved (that is, a reverse lookup failed). You can also
|
||||
// receive this error if the client domain has been identified as an open relay
|
||||
// or source for unsolicited e-mail (spam). For details, see RFC 2505, which is
|
||||
// available at http://www.ietf.org/.
|
||||
LocalErrorInProcessing = 451,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service does not have sufficient storage to complete the request.
|
||||
InsufficientStorage = 452,
|
||||
//
|
||||
// Summary:
|
||||
// The client was not authenticated or is not allowed to send mail using the specified
|
||||
// SMTP host.
|
||||
ClientNotPermitted = 454,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service does not recognize the specified command.
|
||||
CommandUnrecognized = 500,
|
||||
//
|
||||
// Summary:
|
||||
// The syntax used to specify a command or parameter is incorrect.
|
||||
SyntaxError = 501,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service does not implement the specified command.
|
||||
CommandNotImplemented = 502,
|
||||
//
|
||||
// Summary:
|
||||
// The commands were sent in the incorrect sequence.
|
||||
BadCommandSequence = 503,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP service does not implement the specified command parameter.
|
||||
CommandParameterNotImplemented = 504,
|
||||
//
|
||||
// Summary:
|
||||
// The SMTP server is configured to accept only TLS connections, and the SMTP client
|
||||
// is attempting to connect by using a non-TLS connection. The solution is for the
|
||||
// user to set EnableSsl=true on the SMTP Client.
|
||||
MustIssueStartTlsFirst = 530,
|
||||
//
|
||||
// Summary:
|
||||
// The destination mailbox was not found or could not be accessed.
|
||||
MailboxUnavailable = 550,
|
||||
//
|
||||
// Summary:
|
||||
// The user mailbox is not located on the receiving server. You should resend using
|
||||
// the supplied address information.
|
||||
UserNotLocalTryAlternatePath = 551,
|
||||
//
|
||||
// Summary:
|
||||
// The message is too large to be stored in the destination mailbox.
|
||||
ExceededStorageAllocation = 552,
|
||||
//
|
||||
// Summary:
|
||||
// The syntax used to specify the destination mailbox is incorrect.
|
||||
MailboxNameNotAllowed = 553,
|
||||
//
|
||||
// Summary:
|
||||
// The transaction failed.
|
||||
TransactionFailed = 554
|
||||
}
|
||||
|
||||
public static class MailErrorCodeUtils
|
||||
{
|
||||
#if STANDARD
|
||||
public static eMailErrorCode FromNetStandardMailCode(SmtpStatusCode code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case SmtpStatusCode.BadCommandSequence:
|
||||
return eMailErrorCode.BadCommandSequence;
|
||||
case SmtpStatusCode.CannotVerifyUserWillAttemptDelivery:
|
||||
return eMailErrorCode.CannotVerifyUserWillAttemptDelivery;
|
||||
case SmtpStatusCode.ClientNotPermitted:
|
||||
return eMailErrorCode.ClientNotPermitted;
|
||||
case SmtpStatusCode.CommandNotImplemented:
|
||||
return eMailErrorCode.CommandNotImplemented;
|
||||
case SmtpStatusCode.CommandParameterNotImplemented:
|
||||
return eMailErrorCode.CommandParameterNotImplemented;
|
||||
case SmtpStatusCode.CommandUnrecognized:
|
||||
return eMailErrorCode.CommandUnrecognized;
|
||||
case SmtpStatusCode.ExceededStorageAllocation:
|
||||
return eMailErrorCode.ExceededStorageAllocation;
|
||||
case SmtpStatusCode.GeneralFailure:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case SmtpStatusCode.HelpMessage:
|
||||
return eMailErrorCode.HelpMessage;
|
||||
case SmtpStatusCode.InsufficientStorage:
|
||||
return eMailErrorCode.InsufficientStorage;
|
||||
case SmtpStatusCode.LocalErrorInProcessing:
|
||||
return eMailErrorCode.LocalErrorInProcessing;
|
||||
case SmtpStatusCode.MailboxBusy:
|
||||
return eMailErrorCode.MailboxBusy;
|
||||
case SmtpStatusCode.MailboxNameNotAllowed:
|
||||
return eMailErrorCode.MailboxNameNotAllowed;
|
||||
case SmtpStatusCode.MailboxUnavailable:
|
||||
return eMailErrorCode.MailboxUnavailable;
|
||||
case SmtpStatusCode.MustIssueStartTlsFirst:
|
||||
return eMailErrorCode.MustIssueStartTlsFirst;
|
||||
case SmtpStatusCode.Ok:
|
||||
return eMailErrorCode.Ok;
|
||||
case SmtpStatusCode.ServiceClosingTransmissionChannel:
|
||||
return eMailErrorCode.ServiceClosingTransmissionChannel;
|
||||
case SmtpStatusCode.ServiceNotAvailable:
|
||||
return eMailErrorCode.ServiceNotAvailable;
|
||||
case SmtpStatusCode.ServiceReady:
|
||||
return eMailErrorCode.ServiceReady;
|
||||
case SmtpStatusCode.StartMailInput:
|
||||
return eMailErrorCode.StartMailInput;
|
||||
case SmtpStatusCode.SyntaxError:
|
||||
return eMailErrorCode.SyntaxError;
|
||||
case SmtpStatusCode.SystemStatus:
|
||||
return eMailErrorCode.SystemStatus;
|
||||
case SmtpStatusCode.TransactionFailed:
|
||||
return eMailErrorCode.TransactionFailed;
|
||||
case SmtpStatusCode.UserNotLocalTryAlternatePath:
|
||||
return eMailErrorCode.UserNotLocalTryAlternatePath;
|
||||
case SmtpStatusCode.UserNotLocalWillForward:
|
||||
return eMailErrorCode.UserNotLocalWillForward;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(code), code, null);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if SIMPLSHARP
|
||||
public static eMailErrorCode FromSimplMailCode(CrestronMailFunctions.SendMailErrorCodes code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_OK:
|
||||
return eMailErrorCode.Ok;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_FATAL:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_ILLEGAL_CMD:
|
||||
return eMailErrorCode.CommandUnrecognized;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_CONNECT:
|
||||
return eMailErrorCode.ServiceNotAvailable;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_SEND:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_RECV:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_NU_CONNECT:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_NU_BUFFERS:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_AUTHENTICATION:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ERROR_AUTH_LOGIN_UNSUPPORTED:
|
||||
return eMailErrorCode.MustIssueStartTlsFirst;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_INV_PARAM:
|
||||
return eMailErrorCode.SyntaxError;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_ETHER_NOT_ENABLED:
|
||||
return eMailErrorCode.ServiceNotAvailable;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_NO_SERVER_ADDRESS:
|
||||
return eMailErrorCode.ServiceNotAvailable;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_SEND_FAILED:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_GENERAL_SENDMAIL_ERROR:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
case CrestronMailFunctions.SendMailErrorCodes.SMTP_INVALID_FIRMWARE:
|
||||
return eMailErrorCode.GeneralFailure;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("code");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,14 @@
|
||||
public StringEventArgs(string data) : base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public StringEventArgs(StringEventArgs eventArgs)
|
||||
: base(eventArgs.Data)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,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)
|
||||
{
|
||||
@@ -111,6 +112,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="key"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
[PublicAPI]
|
||||
public static TValue GetOrAddDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key,
|
||||
TValue defaultValue)
|
||||
@@ -122,8 +124,10 @@ 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>
|
||||
@@ -452,12 +456,26 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Dictionary<TValue, TKey> ToInverse<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
|
||||
public static Dictionary<TValue, List<TKey>> ToInverse<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
|
||||
Dictionary<TValue, List<TKey>> output = new Dictionary<TValue, List<TKey>>();
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in extends)
|
||||
{
|
||||
List<TKey> keys;
|
||||
if (!output.TryGetValue(kvp.Value, out keys))
|
||||
{
|
||||
keys = new List<TKey>();
|
||||
output.Add(kvp.Value, keys);
|
||||
}
|
||||
|
||||
keys.Add(kvp.Key);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -3,25 +3,37 @@ 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
|
||||
public static class JsonReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the object value.
|
||||
/// 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 = new JsonSerializer();
|
||||
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="value"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="converter"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteObject(this JsonWriter extends, object value, JsonSerializer serializer,
|
||||
JsonConverter converter)
|
||||
/// <returns></returns>
|
||||
public static T ReadAsObject<T>(this JsonReader extends, JsonSerializer serializer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -29,36 +41,48 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (converter == null)
|
||||
throw new ArgumentNullException("converter");
|
||||
|
||||
JObject jObject = JObject.FromObject(value, serializer);
|
||||
jObject.WriteTo(extends, converter);
|
||||
return serializer.Deserialize<T>(extends);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the type value.
|
||||
/// Reads through the current object token and calls the callback for each property value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="type"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteType(this JsonWriter extends, Type type)
|
||||
/// <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 (type == null)
|
||||
{
|
||||
extends.WriteNull();
|
||||
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);
|
||||
}
|
||||
|
||||
// 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>
|
||||
@@ -167,55 +191,18 @@ namespace ICD.Common.Utils.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// Gets the current value as a guid.
|
||||
/// </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)
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Guid GetValueAsGuid(this JsonReader extends)
|
||||
{
|
||||
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();
|
||||
string stringValue = extends.GetValueAsString();
|
||||
return new Guid(stringValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -285,90 +272,5 @@ namespace ICD.Common.Utils.Extensions
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
83
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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>
|
||||
/// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -37,7 +37,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");
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
index = thisIndex;
|
||||
first = item;
|
||||
|
||||
if (index == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
@@ -54,7 +57,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.StartsWith(character.ToString());
|
||||
return extends.Length > 0 && character == extends[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +72,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.EndsWith(character.ToString());
|
||||
return extends.Length > 0 && character == extends[extends.Length - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,26 +104,18 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<string> SplitIterator(string value, char delimeter, int count)
|
||||
{
|
||||
if (count < 2)
|
||||
while (count > 1)
|
||||
{
|
||||
yield return value;
|
||||
yield break;
|
||||
int index = value.IndexOf(delimeter);
|
||||
if (index < 0)
|
||||
break;
|
||||
|
||||
yield return value.Substring(0, index);
|
||||
value = value.Substring(index + 1);
|
||||
count--;
|
||||
}
|
||||
|
||||
int index = value.IndexOf(delimeter);
|
||||
if (index < 0)
|
||||
{
|
||||
yield return value;
|
||||
yield break;
|
||||
}
|
||||
|
||||
string first = value.Substring(0, index);
|
||||
string second = value.Substring(index + 1);
|
||||
count--;
|
||||
|
||||
yield return first;
|
||||
foreach (string item in second.Split(delimeter, count))
|
||||
yield return item;
|
||||
yield return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -142,97 +137,6 @@ namespace ICD.Common.Utils.Extensions
|
||||
.Select(i => extends.Substring(i * chunkSize, Math.Min(chunkSize, extends.Length - (i * chunkSize))));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a string by a given substring.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="delimeter"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<string> Split(this string extends, string delimeter)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (delimeter == null)
|
||||
throw new ArgumentNullException("delimeter");
|
||||
|
||||
return SplitIterator(extends, delimeter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a string by a given substring.
|
||||
/// Taken from
|
||||
/// https://social.msdn.microsoft.com/Forums/en-US/914a350f-e0e9-45e0-91a4-6b4b2168e780/string-split-function
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="delimeter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<string> SplitIterator(string value, string delimeter)
|
||||
{
|
||||
int dSum = 0;
|
||||
int sSum = 0;
|
||||
int length = value.Length;
|
||||
int delimiterLength = delimeter.Length;
|
||||
|
||||
if (delimiterLength == 0 || length == 0 || length < delimiterLength)
|
||||
{
|
||||
yield return value;
|
||||
yield break;
|
||||
}
|
||||
|
||||
char[] cd = delimeter.ToCharArray();
|
||||
char[] cs = value.ToCharArray();
|
||||
|
||||
for (int i = 0; i < delimiterLength; i++)
|
||||
{
|
||||
dSum += cd[i];
|
||||
sSum += cs[i];
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
for (int i = start; i < length - delimiterLength; i++)
|
||||
{
|
||||
if (i >= start && dSum == sSum && value.Substring(i, delimiterLength) == delimeter)
|
||||
{
|
||||
yield return value.Substring(start, i - start);
|
||||
start = i + delimiterLength;
|
||||
}
|
||||
|
||||
sSum += cs[i + delimiterLength] - cs[i];
|
||||
}
|
||||
|
||||
if (dSum == sSum && value.Substring(length - delimiterLength, delimiterLength) == delimeter)
|
||||
{
|
||||
yield return value.Substring(start, length - delimiterLength - start);
|
||||
yield return string.Empty;
|
||||
}
|
||||
else
|
||||
yield return value.Substring(start, length - start);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a string by the given substrings.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="delimeters"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<string> Split(this string extends, IEnumerable<string> delimeters)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (delimeters == null)
|
||||
throw new ArgumentNullException("delimeters");
|
||||
|
||||
string[] delimitersArray = delimeters as string[] ?? delimeters.ToArray();
|
||||
return delimitersArray.Length == 0
|
||||
? new[] {extends}
|
||||
: extends.Split(delimitersArray.First())
|
||||
.SelectMany(s => s.Split(delimitersArray.Skip(1)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes whitespace from the string.
|
||||
/// </summary>
|
||||
@@ -248,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>
|
||||
@@ -261,8 +189,9 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
if (characters == null)
|
||||
throw new ArgumentNullException("characters");
|
||||
var cSet = characters.ToIcdHashSet();
|
||||
|
||||
return new string(extends.Where(c => !characters.Contains(c)).ToArray());
|
||||
return new string(extends.Where(c => !cSet.Contains(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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>
|
||||
@@ -307,6 +311,128 @@ 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.Add(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.Add(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;
|
||||
for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
|
||||
{
|
||||
char current = fullyQualifiedTypeName[i];
|
||||
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>
|
||||
@@ -317,45 +443,48 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
// Nullable
|
||||
Type nullableType = Nullable.GetUnderlyingType(extends);
|
||||
if (nullableType != null)
|
||||
return nullableType.GetSyntaxName() + "?";
|
||||
|
||||
if (!(extends.IsGenericType && extends.Name.Contains('`')))
|
||||
// Generic
|
||||
if (extends.IsGenericType)
|
||||
{
|
||||
switch (extends.Name)
|
||||
StringBuilder sb = new StringBuilder(extends.Name.Substring(0, extends.Name.IndexOf('`')));
|
||||
sb.Append('<');
|
||||
|
||||
bool first = true;
|
||||
foreach (Type t in extends.GetGenericArguments())
|
||||
{
|
||||
case "String":
|
||||
return "string";
|
||||
case "Int32":
|
||||
return "int";
|
||||
case "Decimal":
|
||||
return "decimal";
|
||||
case "Object":
|
||||
return "object";
|
||||
case "Void":
|
||||
return "void";
|
||||
|
||||
default:
|
||||
return string.IsNullOrEmpty(extends.FullName) ? extends.Name : extends.FullName;
|
||||
if (!first)
|
||||
sb.Append(',');
|
||||
sb.Append(t.GetSyntaxName());
|
||||
first = false;
|
||||
}
|
||||
|
||||
sb.Append('>');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(extends.Name.Substring(0, extends.Name.IndexOf('`')));
|
||||
sb.Append('<');
|
||||
|
||||
bool first = true;
|
||||
foreach (Type t in extends.GetGenericArguments())
|
||||
// Default
|
||||
switch (extends.Name)
|
||||
{
|
||||
if (!first)
|
||||
sb.Append(',');
|
||||
sb.Append(t.GetSyntaxName());
|
||||
first = false;
|
||||
case "String":
|
||||
return "string";
|
||||
case "Int32":
|
||||
return "int";
|
||||
case "Decimal":
|
||||
return "decimal";
|
||||
case "Object":
|
||||
return "object";
|
||||
case "Void":
|
||||
return "void";
|
||||
|
||||
default:
|
||||
return extends.Name;
|
||||
}
|
||||
|
||||
sb.Append('>');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
<None Remove="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -74,8 +75,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes\AbstractIcdAttribute.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" />
|
||||
@@ -84,7 +85,12 @@
|
||||
<Compile Include="Comparers\PredicateComparer.cs" />
|
||||
<Compile Include="Comparers\SequenceComparer.cs" />
|
||||
<Compile Include="ConsoleColor.cs" />
|
||||
<Compile Include="Email\EmailClient.cs" />
|
||||
<Compile Include="Email\eMailErrorCode.cs" />
|
||||
<Compile Include="Email\EmailStringCollection.cs" />
|
||||
<Compile Include="EncodingUtils.cs" />
|
||||
<Compile Include="Csv\CsvWriter.cs" />
|
||||
<Compile Include="Csv\CsvWriterSettings.cs" />
|
||||
<Compile Include="EventArguments\BoolEventArgs.cs" />
|
||||
<Compile Include="EventArguments\CharEventArgs.cs" />
|
||||
<Compile Include="EventArguments\DateTimeEventArgs.cs" />
|
||||
@@ -99,16 +105,19 @@
|
||||
<Compile Include="Extensions\BoolExtensions.cs" />
|
||||
<Compile Include="Extensions\ByteExtensions.cs" />
|
||||
<Compile Include="Extensions\DayOfWeekExtensions.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="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" />
|
||||
@@ -146,7 +155,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" />
|
||||
@@ -195,12 +204,16 @@
|
||||
<Compile Include="Timers\SafeTimer.cs" />
|
||||
<Compile Include="TryUtils.cs" />
|
||||
<Compile Include="UriUtils.cs" />
|
||||
<Compile Include="Xml\AbstractGenericXmlConverter.cs" />
|
||||
<Compile Include="Xml\AbstractXmlConverter.cs" />
|
||||
<Compile Include="Xml\DefaultXmlConverter.cs" />
|
||||
<Compile Include="Xml\IcdXmlConvert.cs" />
|
||||
<Compile Include="Xml\IcdXmlDocument.cs" />
|
||||
<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" />
|
||||
<Compile Include="Xml\XmlUtils.cs" />
|
||||
<None Include="Properties\ControlSystem.cfg" />
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -94,5 +94,11 @@ namespace ICD.Common.Utils.IO
|
||||
{
|
||||
return new IcdFileStream(File.Create(path));
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static IcdStreamWriter AppendText(string path)
|
||||
{
|
||||
return new IcdStreamWriter(File.AppendText(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Crestron.SimplSharp.CrestronIO;
|
||||
#else
|
||||
using System.IO;
|
||||
#endif
|
||||
using System.Text;
|
||||
|
||||
namespace ICD.Common.Utils.IO
|
||||
{
|
||||
@@ -32,5 +33,11 @@ namespace ICD.Common.Utils.IO
|
||||
WrappedFileStream.Dispose();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Write(string data, Encoding encoding)
|
||||
{
|
||||
byte[] info = encoding.GetBytes(data);
|
||||
WrappedFileStream.Write(info, 0, info.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
#else
|
||||
@@ -69,16 +70,16 @@ namespace ICD.Common.Utils.IO
|
||||
return Path.ChangeExtension(path, ext);
|
||||
}
|
||||
|
||||
public static string GetRelativePath(string folder, string filespec)
|
||||
{
|
||||
Uri pathUri = new Uri(filespec);
|
||||
// Folders must end in a slash
|
||||
if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
folder += Path.DirectorySeparatorChar;
|
||||
}
|
||||
Uri folderUri = new Uri(folder);
|
||||
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
|
||||
}
|
||||
public static string GetRelativePath(string folder, string filespec)
|
||||
{
|
||||
Uri pathUri = new Uri(filespec);
|
||||
|
||||
// Folders must end in a slash
|
||||
if (!folder.EndsWith(Path.DirectorySeparatorChar))
|
||||
folder += Path.DirectorySeparatorChar;
|
||||
|
||||
Uri folderUri = new Uri(folder);
|
||||
return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
ICD.Common.Utils/IO/IcdStreamWriter.cs
Normal file
21
ICD.Common.Utils/IO/IcdStreamWriter.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
#elif STANDARD
|
||||
using System.IO;
|
||||
#endif
|
||||
|
||||
namespace ICD.Common.Utils.IO
|
||||
{
|
||||
public sealed class IcdStreamWriter : IcdTextWriter
|
||||
{
|
||||
public StreamWriter WrappedStreamWriter { get { return WrappedTextWriter as StreamWriter; } }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="baseStreamWriter"></param>
|
||||
public IcdStreamWriter(StreamWriter baseStreamWriter) : base(baseStreamWriter)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,17 +45,23 @@ 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)
|
||||
{
|
||||
Print(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
Print(message);
|
||||
}
|
||||
#else
|
||||
Print(message, args);
|
||||
#endif
|
||||
|
||||
Print(message);
|
||||
}
|
||||
|
||||
public static void PrintLine(string message)
|
||||
@@ -90,10 +100,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 +135,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;
|
||||
|
||||
@@ -12,7 +12,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>
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
SimplSharp,
|
||||
SimplSharpPro,
|
||||
SimplSharpProMono,
|
||||
Standard
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -62,6 +66,7 @@ namespace ICD.Common.Utils
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public IcdUriBuilder()
|
||||
: this((Uri)null)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -70,7 +75,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
public IcdUriBuilder(string uri)
|
||||
: this(new Uri(uri))
|
||||
: this(new Uri(uri, UriKind.RelativeOrAbsolute))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -80,6 +85,12 @@ namespace ICD.Common.Utils
|
||||
/// <param name="uri"></param>
|
||||
public IcdUriBuilder(Uri uri)
|
||||
{
|
||||
if (uri == null)
|
||||
return;
|
||||
|
||||
if (!uri.IsAbsoluteUri)
|
||||
uri = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri);
|
||||
|
||||
Fragment = uri.Fragment;
|
||||
Host = uri.Host;
|
||||
Password = uri.GetPassword();
|
||||
@@ -103,7 +114,7 @@ namespace ICD.Common.Utils
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// Scheme
|
||||
string scheme = string.IsNullOrEmpty(Scheme) ? "http" : Scheme;
|
||||
string scheme = string.IsNullOrEmpty(Scheme) ? Uri.UriSchemeHttp : Scheme;
|
||||
builder.Append(scheme);
|
||||
builder.Append(':');
|
||||
|
||||
@@ -152,6 +163,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 '&' 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
@@ -29,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);
|
||||
}
|
||||
|
||||
@@ -116,30 +111,15 @@ 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();
|
||||
}
|
||||
T output = Instantiate();
|
||||
|
||||
// Get the property
|
||||
if (reader.TokenType != JsonToken.PropertyName)
|
||||
continue;
|
||||
string property = (string)reader.Value;
|
||||
|
||||
// Read into the value
|
||||
reader.Read();
|
||||
|
||||
ReadProperty(property, reader, output, serializer);
|
||||
}
|
||||
reader.ReadObject(serializer, (p, r, s) => ReadProperty(p, r, output, s));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -22,28 +22,6 @@ namespace ICD.Common.Utils.Json
|
||||
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>
|
||||
@@ -87,31 +65,6 @@ namespace ICD.Common.Utils.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 +187,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 +286,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
89
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
89
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
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)
|
||||
return parse.Invoke(null, new[] {reader.Value});
|
||||
|
||||
throw new ArgumentException(
|
||||
string.Format("{0} does not have a 'static {0} Parse(string)' method.", objectType.Name),
|
||||
"objectType");
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,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
|
||||
@@ -26,10 +34,23 @@ namespace ICD.Common.Utils
|
||||
public static string ProgramPath { get { return IcdDirectory.GetApplicationDirectory(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the NVRAM directory.
|
||||
/// Gets the path to the root config directory,
|
||||
/// which contains common and program-specific config directories.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string NvramPath { get { return Join(RootPath, "NVRAM"); } }
|
||||
public static string RootConfigPath
|
||||
{
|
||||
get
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
return Join(RootPath, "User");
|
||||
#elif LINUX
|
||||
return Join(RootPath, "opt", "ICD.Connect");
|
||||
#else
|
||||
return Join(RootPath, "ProgramData", "ICD.Connect");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the absolute path to the configuration directory.
|
||||
@@ -40,8 +61,11 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
return Join(RootConfigPath, "ProgramConfig");
|
||||
|
||||
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
|
||||
return Join(NvramPath, directoryName);
|
||||
return Join(RootConfigPath, directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +73,7 @@ namespace ICD.Common.Utils
|
||||
/// Returns the absolute path to the common configuration directory.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string CommonConfigPath { get { return Join(NvramPath, "CommonConfig"); } }
|
||||
public static string CommonConfigPath { get { return Join(RootConfigPath, "CommonConfig"); } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the absolute path to the common config library directory.
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace ICD.Common.Utils
|
||||
return output;
|
||||
}
|
||||
|
||||
foreach (string line in progInfo.Split(new[] {"\n\r", "\r\n", "\n", "\r"}))
|
||||
foreach (string line in progInfo.Split(new[] {'\r', '\n'}))
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
|
||||
@@ -8,17 +8,11 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
public static partial class ProgramUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the program number.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static uint ProgramNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the program number.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static uint ProgramNumber { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compile date of the program.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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("5.0.0.0")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2019")]
|
||||
[assembly: AssemblyVersion("9.1.0.0")]
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -97,23 +98,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>
|
||||
@@ -159,9 +160,9 @@ namespace ICD.Common.Utils
|
||||
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))
|
||||
@@ -214,10 +215,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))
|
||||
@@ -235,26 +235,38 @@ namespace ICD.Common.Utils
|
||||
return null;
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public static Dictionary<T, IEnumerable<T>> BreadthFirstSearchManyDestinations<T>(T root,
|
||||
IEnumerable<T> destinations,
|
||||
Func<T, IEnumerable<T>>
|
||||
getChildren)
|
||||
/// <summary>
|
||||
/// Returns the shortest path from root to each destination via breadth-first search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="destinations"></param>
|
||||
/// <param name="getChildren"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||
BreadthFirstSearchPathManyDestinations<T>(T root, IEnumerable<T> destinations, Func<T, IEnumerable<T>> getChildren)
|
||||
{
|
||||
if (destinations == null)
|
||||
throw new ArgumentNullException("destinations");
|
||||
|
||||
if (getChildren == null)
|
||||
throw new ArgumentNullException("getChildren");
|
||||
|
||||
return BreadthFirstSearchPathManyDestinations(root, destinations, getChildren, EqualityComparer<T>.Default);
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
public static Dictionary<T, IEnumerable<T>> BreadthFirstSearchPathManyDestinations<T>(T root,
|
||||
IEnumerable<T>
|
||||
destinations,
|
||||
Func<T, IEnumerable<T>>
|
||||
getChildren,
|
||||
IEqualityComparer<T>
|
||||
comparer)
|
||||
/// <summary>
|
||||
/// Returns the shortest path from root to each destination via breadth-first search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="destinations"></param>
|
||||
/// <param name="getChildren"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||
BreadthFirstSearchPathManyDestinations<T>(T root, IEnumerable<T> destinations, Func<T, IEnumerable<T>> getChildren,
|
||||
IEqualityComparer<T> comparer)
|
||||
{
|
||||
if (destinations == null)
|
||||
throw new ArgumentNullException("destinations");
|
||||
@@ -266,18 +278,17 @@ namespace ICD.Common.Utils
|
||||
throw new ArgumentNullException("comparer");
|
||||
|
||||
IcdHashSet<T> destinationsToBeProcessed = new IcdHashSet<T>(destinations);
|
||||
Dictionary<T, IEnumerable<T>> pathsToReturn = new Dictionary<T, IEnumerable<T>>();
|
||||
|
||||
// Edge case, root is the destination
|
||||
foreach (T destination in
|
||||
destinationsToBeProcessed.Where(destination => comparer.Equals(root, destination)).ToArray())
|
||||
{
|
||||
destinationsToBeProcessed.Remove(destination);
|
||||
pathsToReturn.Add(destination, new[] {root});
|
||||
destinationsToBeProcessed.Remove(destination);
|
||||
yield return new KeyValuePair<T, IEnumerable<T>>(destination, new[] {root});
|
||||
}
|
||||
|
||||
if (destinationsToBeProcessed.Count == 0)
|
||||
return pathsToReturn;
|
||||
yield break;
|
||||
|
||||
Queue<T> queue = new Queue<T>();
|
||||
queue.Enqueue(root);
|
||||
@@ -298,15 +309,15 @@ namespace ICD.Common.Utils
|
||||
destinationsToBeProcessed.Where(destination => comparer.Equals(closureNode, destination)).ToArray())
|
||||
{
|
||||
destinationsToBeProcessed.Remove(destination);
|
||||
pathsToReturn.Add(destination, GetPath(destination, root, nodeParents, comparer).Reverse());
|
||||
|
||||
yield return
|
||||
new KeyValuePair<T, IEnumerable<T>>(destination, GetPath(destination, root, nodeParents, comparer).Reverse());
|
||||
}
|
||||
|
||||
if (destinationsToBeProcessed.Count == 0)
|
||||
return pathsToReturn;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
return pathsToReturn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
@@ -167,6 +168,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 +184,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 +198,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 +211,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)
|
||||
@@ -237,6 +242,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 +251,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 +270,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Assembly LoadAssemblyFromPath(string path)
|
||||
{
|
||||
if (path == null)
|
||||
@@ -325,8 +337,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 +353,58 @@ 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;
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
|
||||
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;
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
|
||||
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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(", ");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -423,7 +423,12 @@ namespace ICD.Common.Utils
|
||||
[PublicAPI]
|
||||
public static string Repeat(string input, int count)
|
||||
{
|
||||
return count == 0 ? string.Empty : new StringBuilder().Insert(0, input, count).ToString();
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
|
||||
return input == null || count == 0
|
||||
? string.Empty
|
||||
: new StringBuilder().Insert(0, input, count).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -559,6 +564,30 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats "0xFF" to an IPID.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryFromIpIdString(string value, out byte result)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
result = 0;
|
||||
|
||||
try
|
||||
{
|
||||
result = (byte)Convert.ToInt64(value, 16);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all whitespace from the string.
|
||||
/// </summary>
|
||||
@@ -566,7 +595,7 @@ namespace ICD.Common.Utils
|
||||
/// <returns></returns>
|
||||
public static string RemoveWhitespace(string text)
|
||||
{
|
||||
return text == null ? null : new string(text.Where(c => !Char.IsWhiteSpace(c)).ToArray());
|
||||
return text == null ? null : text.RemoveWhitespace();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
@@ -18,6 +19,8 @@ namespace ICD.Common.Utils.Timers
|
||||
|
||||
private readonly Stopwatch m_Stopwatch;
|
||||
|
||||
private static int s_ProfileIndentCount;
|
||||
|
||||
#region Properties
|
||||
|
||||
public long ElapsedTicks { get { return m_Stopwatch.ElapsedTicks; } }
|
||||
@@ -104,9 +107,18 @@ namespace ICD.Common.Utils.Timers
|
||||
if (action == null)
|
||||
throw new ArgumentNullException("action");
|
||||
|
||||
IcdStopwatch stopwatch = StartNew();
|
||||
action();
|
||||
PrintProfile(stopwatch.ElapsedTicks, name);
|
||||
s_ProfileIndentCount++;
|
||||
|
||||
try
|
||||
{
|
||||
IcdStopwatch stopwatch = StartNew();
|
||||
action();
|
||||
PrintProfile(stopwatch.ElapsedTicks, name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_ProfileIndentCount--;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,11 +134,20 @@ namespace ICD.Common.Utils.Timers
|
||||
if (func == null)
|
||||
throw new ArgumentNullException("func");
|
||||
|
||||
IcdStopwatch stopwatch = StartNew();
|
||||
T output = func();
|
||||
PrintProfile(stopwatch.ElapsedTicks, name);
|
||||
s_ProfileIndentCount++;
|
||||
|
||||
return output;
|
||||
try
|
||||
{
|
||||
IcdStopwatch stopwatch = StartNew();
|
||||
T output = func();
|
||||
PrintProfile(stopwatch.ElapsedTicks, name);
|
||||
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_ProfileIndentCount--;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -192,12 +213,16 @@ namespace ICD.Common.Utils.Timers
|
||||
|
||||
// TODO - Print a fancy table with a total duration for the sequence
|
||||
|
||||
List<T> output = new List<T>();
|
||||
|
||||
using (IEnumerator<T> enumerator = enumerable.GetEnumerator())
|
||||
{
|
||||
// ReSharper disable once AccessToDisposedClosure
|
||||
while (Profile(() => enumerator.MoveNext(), name))
|
||||
yield return enumerator.Current;
|
||||
output.Add(enumerator.Current);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -208,20 +233,27 @@ namespace ICD.Common.Utils.Timers
|
||||
/// <param name="name"></param>
|
||||
public static void Profile(EventHandler eventHandler, object sender, string name)
|
||||
{
|
||||
if (eventHandler == null)
|
||||
s_ProfileIndentCount++;
|
||||
|
||||
try
|
||||
{
|
||||
PrintProfile(0, string.Format("{0} - No invocations", name));
|
||||
return;
|
||||
if (eventHandler == null)
|
||||
{
|
||||
PrintProfile(0, string.Format("{0} - No invocations", name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_ProfileIndentCount--;
|
||||
}
|
||||
|
||||
// TODO - Print a fancy table with a total duration for the event
|
||||
|
||||
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
|
||||
foreach (EventHandler subscriber in eventHandler.GetInvocationList())
|
||||
// ReSharper restore PossibleInvalidCastExceptionInForeachLoop
|
||||
foreach (EventHandler subscriber in eventHandler.GetInvocationList().Cast<EventHandler>())
|
||||
{
|
||||
string subscriberName = string.Format("{0} - {1}.{2}", name, subscriber.Target.GetType().Name,
|
||||
subscriber.GetMethodInfo().GetSignature(true));
|
||||
subscriber.GetMethodInfo().GetSignature(true));
|
||||
|
||||
EventHandler subscriber1 = subscriber;
|
||||
Profile(() => subscriber1(sender, EventArgs.Empty), subscriberName);
|
||||
@@ -239,20 +271,27 @@ namespace ICD.Common.Utils.Timers
|
||||
public static void Profile<T>(EventHandler<T> eventHandler, object sender, T eventArgs, string name)
|
||||
where T : EventArgs
|
||||
{
|
||||
if (eventHandler == null)
|
||||
s_ProfileIndentCount++;
|
||||
|
||||
try
|
||||
{
|
||||
PrintProfile(0, string.Format("{0} - No invocations", name));
|
||||
return;
|
||||
if (eventHandler == null)
|
||||
{
|
||||
PrintProfile(0, string.Format("{0} - No invocations", name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_ProfileIndentCount--;
|
||||
}
|
||||
|
||||
// TODO - Print a fancy table with a total duration for the event
|
||||
|
||||
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
|
||||
foreach (EventHandler<T> subscriber in eventHandler.GetInvocationList())
|
||||
// ReSharper restore PossibleInvalidCastExceptionInForeachLoop
|
||||
foreach (EventHandler<T> subscriber in eventHandler.GetInvocationList().Cast<EventHandler<T>>())
|
||||
{
|
||||
string subscriberName = string.Format("{0} - {1}.{2}", name, subscriber.Target.GetType().Name,
|
||||
subscriber.GetMethodInfo().GetSignature(true));
|
||||
subscriber.GetMethodInfo().GetSignature(true));
|
||||
|
||||
EventHandler<T> subscriber1 = subscriber;
|
||||
Profile(() => subscriber1(sender, eventArgs), subscriberName);
|
||||
@@ -269,8 +308,13 @@ namespace ICD.Common.Utils.Timers
|
||||
if (elapsed >= RED_MILLISECONDS)
|
||||
color = eConsoleColor.Red;
|
||||
|
||||
IcdConsole.Print(color, "{0:n}ms", elapsed);
|
||||
IcdConsole.PrintLine(" to execute {0}", name);
|
||||
string padding = null;
|
||||
|
||||
if (s_ProfileIndentCount > 0)
|
||||
padding = StringUtils.Repeat(" ", s_ProfileIndentCount - 1);
|
||||
|
||||
IcdConsole.Print(color, "{0}{1:n}ms ", padding, elapsed);
|
||||
IcdConsole.PrintLine("to execute {0}", name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -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.
|
||||
@@ -88,6 +88,8 @@ namespace ICD.Common.Utils.Timers
|
||||
Stop();
|
||||
m_Timer.Dispose();
|
||||
|
||||
m_Callback = null;
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
183
ICD.Common.Utils/Xml/AbstractGenericXmlConverter.cs
Normal file
183
ICD.Common.Utils/Xml/AbstractGenericXmlConverter.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronXml;
|
||||
#else
|
||||
using System.Xml;
|
||||
#endif
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
public abstract class AbstractGenericXmlConverter<T> : AbstractXmlConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of T.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract T Instantiate();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value">The value.</param>
|
||||
public sealed override void WriteXml(IcdXmlTextWriter writer, string elementName, object value)
|
||||
{
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteElementString(elementName, null);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteXml(writer, elementName, (T)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value">The value.</param>
|
||||
[PublicAPI]
|
||||
public void WriteXml(IcdXmlTextWriter writer, string elementName, T value)
|
||||
{
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
{
|
||||
writer.WriteElementString(elementName, null);
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartElement(elementName);
|
||||
{
|
||||
WriteAttributes(writer, value);
|
||||
WriteElements(writer, value);
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to write attributes to the root element.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="value"></param>
|
||||
protected virtual void WriteAttributes(IcdXmlTextWriter writer, T value)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to write elements to the writer.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="value"></param>
|
||||
protected virtual void WriteElements(IcdXmlTextWriter writer, T value)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The XmlReader to read from.</param>
|
||||
/// <returns>
|
||||
/// The object value.
|
||||
/// </returns>
|
||||
public sealed override object ReadXml(IcdXmlReader reader)
|
||||
{
|
||||
return ReadXmlTyped(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The XmlReader to read from.</param>
|
||||
/// <returns>
|
||||
/// The object value.
|
||||
/// </returns>
|
||||
[PublicAPI]
|
||||
public virtual T ReadXmlTyped(IcdXmlReader reader)
|
||||
{
|
||||
// Read into the first node
|
||||
if (reader.NodeType != XmlNodeType.Element && !reader.ReadToNextElement())
|
||||
throw new FormatException();
|
||||
|
||||
T output = default(T);
|
||||
bool instantiated = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!instantiated)
|
||||
{
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
if (reader.IsEmptyElement)
|
||||
return default(T);
|
||||
|
||||
output = Instantiate();
|
||||
instantiated = true;
|
||||
|
||||
// Read the root attributes
|
||||
while (reader.MoveToNextAttribute())
|
||||
ReadAttribute(reader, output);
|
||||
|
||||
// Read out of the root element
|
||||
if (!reader.Read())
|
||||
throw new FormatException();
|
||||
continue;
|
||||
|
||||
default:
|
||||
// Keep reading until we reach the root element.
|
||||
if (!reader.Read())
|
||||
throw new FormatException();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
ReadElement(reader, output);
|
||||
continue;
|
||||
|
||||
case XmlNodeType.EndElement:
|
||||
// Read out of the end element
|
||||
reader.Read();
|
||||
return output;
|
||||
|
||||
default:
|
||||
if (!reader.Read())
|
||||
return output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to handle the current attribute.
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="instance"></param>
|
||||
protected virtual void ReadAttribute(IcdXmlReader reader, T instance)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to handle the current element.
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="instance"></param>
|
||||
protected virtual void ReadElement(IcdXmlReader reader, T instance)
|
||||
{
|
||||
// Skip the element
|
||||
reader.Skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
25
ICD.Common.Utils/Xml/AbstractXmlConverter.cs
Normal file
25
ICD.Common.Utils/Xml/AbstractXmlConverter.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
public abstract class AbstractXmlConverter : IXmlConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value">The value.</param>
|
||||
public abstract void WriteXml(IcdXmlTextWriter writer, string elementName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The XmlReader to read from.</param>
|
||||
/// <returns>
|
||||
/// The object value.
|
||||
/// </returns>
|
||||
[PublicAPI]
|
||||
public abstract object ReadXml(IcdXmlReader reader);
|
||||
}
|
||||
}
|
||||
74
ICD.Common.Utils/Xml/DefaultXmlConverter.cs
Normal file
74
ICD.Common.Utils/Xml/DefaultXmlConverter.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
public sealed class DefaultXmlConverter : AbstractXmlConverter
|
||||
{
|
||||
private static readonly Dictionary<Type, DefaultXmlConverter> s_Instances;
|
||||
|
||||
private readonly Type m_SerializeType;
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
/// </summary>
|
||||
static DefaultXmlConverter()
|
||||
{
|
||||
s_Instances = new Dictionary<Type, DefaultXmlConverter>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="serializeType"></param>
|
||||
private DefaultXmlConverter(Type serializeType)
|
||||
{
|
||||
m_SerializeType = serializeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value">The value.</param>
|
||||
public override void WriteXml(IcdXmlTextWriter writer, string elementName, object value)
|
||||
{
|
||||
string elementString = IcdXmlConvert.ToString(value);
|
||||
|
||||
writer.WriteElementString(elementName, elementString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The XmlReader to read from.</param>
|
||||
/// <returns>
|
||||
/// The object value.
|
||||
/// </returns>
|
||||
public override object ReadXml(IcdXmlReader reader)
|
||||
{
|
||||
string value = reader.ReadElementContentAsString();
|
||||
|
||||
return IcdXmlConvert.FromString(m_SerializeType, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the converter instance for the given serialization type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IXmlConverter Instance(Type type)
|
||||
{
|
||||
DefaultXmlConverter converter;
|
||||
|
||||
if (!s_Instances.TryGetValue(type, out converter))
|
||||
{
|
||||
converter = new DefaultXmlConverter(type);
|
||||
s_Instances[type] = converter;
|
||||
}
|
||||
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
ICD.Common.Utils/Xml/IXmlConverter.cs
Normal file
22
ICD.Common.Utils/Xml/IXmlConverter.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
public interface IXmlConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value">The value.</param>
|
||||
void WriteXml(IcdXmlTextWriter writer, string elementName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the XML representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The XmlReader to read from.</param>
|
||||
/// <returns>
|
||||
/// The object value.
|
||||
/// </returns>
|
||||
object ReadXml(IcdXmlReader reader);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICD.Common.Utils.IO;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronXml;
|
||||
#else
|
||||
@@ -9,6 +13,101 @@ namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
public static class IcdXmlConvert
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes the given instance to an xml string.
|
||||
/// </summary>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string SerializeObject(string elementName, object value)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
using (IcdStringWriter stringWriter = new IcdStringWriter(builder))
|
||||
{
|
||||
using (IcdXmlTextWriter writer = new IcdXmlTextWriter(stringWriter))
|
||||
SerializeObject(writer, elementName, value);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given instance to xml.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="elementName"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static void SerializeObject(IcdXmlTextWriter writer, string elementName, object value)
|
||||
{
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
IXmlConverter converter = XmlConverterAttribute.GetConverterForInstance(value);
|
||||
|
||||
converter.WriteXml(writer, elementName, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given xml to an instance of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="xml"></param>
|
||||
/// <returns></returns>
|
||||
public static T DeserializeObject<T>(string xml)
|
||||
{
|
||||
return (T)DeserializeObject(typeof(T), xml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given xml to an instance of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="xml"></param>
|
||||
/// <returns></returns>
|
||||
public static object DeserializeObject(Type type, string xml)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
return DeserializeObject(type, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the current node to an instance of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static T DeserializeObject<T>(IcdXmlReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
return (T)DeserializeObject(typeof(T), reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the current node to an instance of the given type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static object DeserializeObject(Type type, IcdXmlReader reader)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
IXmlConverter converter = XmlConverterAttribute.GetConverterForType(type);
|
||||
|
||||
return converter.ReadXml(reader);
|
||||
}
|
||||
|
||||
public static string ToString(int value)
|
||||
{
|
||||
return XmlConvert.ToString(value);
|
||||
@@ -97,5 +196,49 @@ namespace ICD.Common.Utils.Xml
|
||||
|
||||
return child.ToString();
|
||||
}
|
||||
|
||||
public static T FromString<T>(string value)
|
||||
{
|
||||
return (T)FromString(typeof(T), value);
|
||||
}
|
||||
|
||||
public static object FromString(Type type, string value)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (type == typeof(bool))
|
||||
return bool.Parse(value);
|
||||
if (type == typeof(byte))
|
||||
return byte.Parse(value);
|
||||
if (type == typeof(decimal))
|
||||
return decimal.Parse(value);
|
||||
if (type == typeof(char))
|
||||
return value.Single();
|
||||
if (type == typeof(double))
|
||||
return double.Parse(value);
|
||||
if (type == typeof(Guid))
|
||||
return new Guid(value);
|
||||
if (type == typeof(float))
|
||||
return float.Parse(value);
|
||||
if (type == typeof(int))
|
||||
return int.Parse((value));
|
||||
if (type == typeof(long))
|
||||
return long.Parse(value);
|
||||
if (type == typeof(sbyte))
|
||||
return sbyte.Parse(value);
|
||||
if (type == typeof(short))
|
||||
return short.Parse(value);
|
||||
if (type == typeof(TimeSpan))
|
||||
return TimeSpan.Parse(value);
|
||||
if (type == typeof(uint))
|
||||
return uint.Parse(value);
|
||||
if (type == typeof(ulong))
|
||||
return ulong.Parse(value);
|
||||
if (type == typeof(ushort))
|
||||
return ushort.Parse(value);
|
||||
|
||||
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,19 +138,6 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
public string ReadElementContentAsString()
|
||||
{
|
||||
try
|
||||
{
|
||||
return m_Reader.ReadElementContentAsString();
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
string message = string.Format("Unable to read element '{0}' content as string", m_Reader.Name);
|
||||
throw new IcdXmlException(message, e, e.LineNumber, e.LinePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public string ReadOuterXml()
|
||||
{
|
||||
try
|
||||
@@ -175,6 +162,19 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
public string ReadElementContentAsString()
|
||||
{
|
||||
try
|
||||
{
|
||||
return m_Reader.ReadElementContentAsString();
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
string message = string.Format("Unable to read element '{0}' content as string", m_Reader.Name);
|
||||
throw new IcdXmlException(message, e, e.LineNumber, e.LinePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public long ReadElementContentAsLong()
|
||||
{
|
||||
try
|
||||
@@ -199,6 +199,13 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadElementContentAsBoolean()
|
||||
{
|
||||
// ReadElementContentAsBoolean() is too case sensitive
|
||||
string value = ReadElementContentAsString();
|
||||
return bool.Parse(value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,16 @@ namespace ICD.Common.Utils.Xml
|
||||
|
||||
#region Methods
|
||||
|
||||
public void WriteStartDocument()
|
||||
{
|
||||
m_Writer.WriteStartDocument();
|
||||
}
|
||||
|
||||
public void WriteEndDocument()
|
||||
{
|
||||
m_Writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
public void WriteStartElement(string elementName)
|
||||
{
|
||||
m_Writer.WriteStartElement(elementName);
|
||||
@@ -149,8 +159,8 @@ namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
return new XmlWriterSettings
|
||||
{
|
||||
ConformanceLevel = ConformanceLevel.Fragment,
|
||||
Indent = true
|
||||
Indent = true,
|
||||
ConformanceLevel = ConformanceLevel.Auto
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
91
ICD.Common.Utils/Xml/XmlConverterAttribute.cs
Normal file
91
ICD.Common.Utils/Xml/XmlConverterAttribute.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.Attributes;
|
||||
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
|
||||
public sealed class XmlConverterAttribute : AbstractIcdAttribute
|
||||
{
|
||||
private static readonly Dictionary<Type, IXmlConverter> s_InstanceTypeToConverter;
|
||||
private static readonly Dictionary<Type, IXmlConverter> s_ConverterTypeToConverter;
|
||||
|
||||
private readonly Type m_ConverterType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the converter type.
|
||||
/// </summary>
|
||||
public Type ConverterType { get { return m_ConverterType; } }
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
/// </summary>
|
||||
static XmlConverterAttribute()
|
||||
{
|
||||
s_InstanceTypeToConverter = new Dictionary<Type, IXmlConverter>();
|
||||
s_ConverterTypeToConverter = new Dictionary<Type, IXmlConverter>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="converterType"></param>
|
||||
public XmlConverterAttribute(Type converterType)
|
||||
{
|
||||
m_ConverterType = converterType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XML converter for the given instance.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static IXmlConverter GetConverterForInstance(object value)
|
||||
{
|
||||
return value == null ? DefaultXmlConverter.Instance(typeof(object)) : GetConverterForType(value.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the XML converter for the given type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IXmlConverter GetConverterForType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
IXmlConverter converter;
|
||||
if (!s_InstanceTypeToConverter.TryGetValue(type, out converter))
|
||||
{
|
||||
XmlConverterAttribute attribute = AttributeUtils.GetClassAttribute<XmlConverterAttribute>(type);
|
||||
Type converterType = attribute == null ? null : attribute.ConverterType;
|
||||
|
||||
converter = converterType == null ? DefaultXmlConverter.Instance(type) : LazyLoadConverter(converterType);
|
||||
s_InstanceTypeToConverter[type] = converter;
|
||||
}
|
||||
|
||||
return converter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazy-loads the converter of the given type.
|
||||
/// </summary>
|
||||
/// <param name="converterType"></param>
|
||||
/// <returns></returns>
|
||||
private static IXmlConverter LazyLoadConverter(Type converterType)
|
||||
{
|
||||
if (converterType == null)
|
||||
throw new ArgumentNullException("converterType");
|
||||
|
||||
IXmlConverter converter;
|
||||
if (!s_ConverterTypeToConverter.TryGetValue(converterType, out converter))
|
||||
{
|
||||
converter = ReflectionUtils.CreateInstance(converterType) as IXmlConverter;
|
||||
s_ConverterTypeToConverter[converterType] = converter;
|
||||
}
|
||||
|
||||
return converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronXml;
|
||||
#else
|
||||
@@ -27,7 +28,21 @@ namespace ICD.Common.Utils.Xml
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.GetAttribute(name) != null;
|
||||
string unused;
|
||||
return extends.TryGetAttribute(name, out unused);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the attribute exists.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool TryGetAttribute(this IcdXmlReader extends, string name, out string value)
|
||||
{
|
||||
return (value = extends.GetAttribute(name)) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,22 +51,16 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<IcdXmlAttribute> GetAttributes(this IcdXmlReader extends)
|
||||
public static IEnumerable<KeyValuePair<string, string>> GetAttributes(this IcdXmlReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (!extends.HasAttributes)
|
||||
return Enumerable.Empty<IcdXmlAttribute>();
|
||||
|
||||
List<IcdXmlAttribute> attributes = new List<IcdXmlAttribute>();
|
||||
while (extends.MoveToNextAttribute())
|
||||
attributes.Add(new IcdXmlAttribute(extends.Name, extends.Value));
|
||||
yield return new KeyValuePair<string, string>(extends.Name, extends.Value);
|
||||
|
||||
// Move back to element.
|
||||
extends.MoveToElement();
|
||||
|
||||
return attributes.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -115,7 +124,7 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="callback"></param>
|
||||
[PublicAPI]
|
||||
public static void Recurse(this IcdXmlReader extends, Action<XmlRecursionEventArgs> callback)
|
||||
public static void Recurse(this IcdXmlReader extends, Func<XmlRecursionEventArgs, bool> callback)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -193,14 +202,11 @@ namespace ICD.Common.Utils.Xml
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
try
|
||||
{
|
||||
return extends.GetChildElements(element).First();
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
throw new FormatException("No child element with name " + element, e);
|
||||
}
|
||||
IcdXmlReader output;
|
||||
if (extends.GetChildElements(element).TryFirst(out output))
|
||||
return output;
|
||||
|
||||
throw new FormatException("No child element with name " + element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -304,20 +310,12 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool TryGetChildElementAsString(this IcdXmlReader extends, string element, out string output)
|
||||
{
|
||||
output = null;
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
try
|
||||
{
|
||||
output = extends.GetChildElementsAsString(element).First();
|
||||
return true;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return extends.GetChildElementsAsString(element).TryFirst(out output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -384,6 +382,21 @@ namespace ICD.Common.Utils.Xml
|
||||
return ushort.Parse(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the element content as a short.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static short ReadElementContentAsShort(this IcdXmlReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string content = extends.ReadElementContentAsString();
|
||||
return short.Parse(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the element content as an enum.
|
||||
/// </summary>
|
||||
|
||||
@@ -55,12 +55,12 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="xml"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<IcdXmlAttribute> GetAttributes(string xml)
|
||||
public static IEnumerable<KeyValuePair<string, string>> GetAttributes(string xml)
|
||||
{
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
{
|
||||
reader.ReadToNextElement();
|
||||
return reader.GetAttributes();
|
||||
return reader.GetAttributes().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,13 +71,30 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static IcdXmlAttribute GetAttribute(string xml, string name)
|
||||
public static string GetAttribute(string xml, string name)
|
||||
{
|
||||
IcdXmlAttribute output;
|
||||
if (GetAttributes(xml).TryFirst(a => a.Name == name, out output))
|
||||
return output;
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
{
|
||||
reader.ReadToNextElement();
|
||||
return reader.GetAttribute(name);
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException(string.Format("No attribute with name {0}", name));
|
||||
/// <summary>
|
||||
/// Convenience method for getting attribute by name.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool TryGetAttribute(string xml, string name, out string value)
|
||||
{
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
{
|
||||
reader.ReadToNextElement();
|
||||
return reader.TryGetAttribute(name, out value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,6 +145,21 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the attribute with the given name and returns as a bool.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="ignoreCase"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static T GetAttributeAsEnum<T>(string xml, string name, bool ignoreCase)
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
string attribute = GetAttributeAsString(xml, name);
|
||||
return EnumUtils.Parse<T>(attribute, ignoreCase);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Recurse
|
||||
@@ -138,7 +170,7 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="callback"></param>
|
||||
[PublicAPI]
|
||||
public static void Recurse(string xml, Action<XmlRecursionEventArgs> callback)
|
||||
public static void Recurse(string xml, Func<XmlRecursionEventArgs, bool> callback)
|
||||
{
|
||||
if (callback == null)
|
||||
throw new ArgumentNullException("callback");
|
||||
@@ -152,7 +184,7 @@ namespace ICD.Common.Utils.Xml
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="callback"></param>
|
||||
private static void Recurse(string xml, Stack<string> path, Action<XmlRecursionEventArgs> callback)
|
||||
private static void Recurse(string xml, Stack<string> path, Func<XmlRecursionEventArgs, bool> callback)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException("path");
|
||||
@@ -168,10 +200,11 @@ namespace ICD.Common.Utils.Xml
|
||||
path.Push(childReader.Name);
|
||||
string[] pathOutput = path.Reverse().ToArray(path.Count);
|
||||
|
||||
callback(new XmlRecursionEventArgs(xml, pathOutput));
|
||||
|
||||
foreach (string child in childReader.GetChildElementsAsString())
|
||||
Recurse(child, path, callback);
|
||||
if (callback(new XmlRecursionEventArgs(xml, pathOutput)))
|
||||
{
|
||||
foreach (string child in childReader.GetChildElementsAsString())
|
||||
Recurse(child, path, callback);
|
||||
}
|
||||
|
||||
path.Pop();
|
||||
}
|
||||
@@ -373,6 +406,19 @@ namespace ICD.Common.Utils.Xml
|
||||
return reader.ReadElementContentAsUShort();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of an immediate child.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="childElement"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static short ReadChildElementContentAsShort(string xml, string childElement)
|
||||
{
|
||||
using (IcdXmlReader reader = GetChildElement(xml, childElement))
|
||||
return reader.ReadElementContentAsShort();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of an immediate child.
|
||||
/// </summary>
|
||||
@@ -395,9 +441,8 @@ namespace ICD.Common.Utils.Xml
|
||||
[PublicAPI]
|
||||
public static bool ReadChildElementContentAsBoolean(string xml, string childElement)
|
||||
{
|
||||
// IcdXmlReader.ReadElementContentAsBoolean() is too case sensitive
|
||||
string output = ReadChildElementContentAsString(xml, childElement);
|
||||
return bool.Parse(output);
|
||||
using (IcdXmlReader reader = GetChildElement(xml, childElement))
|
||||
return reader.ReadElementContentAsBoolean();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -534,6 +579,25 @@ namespace ICD.Common.Utils.Xml
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the immediate child. Returns null if the child element was not found.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="childElement"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static short? TryReadChildElementContentAsShort(string xml, string childElement)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReadChildElementContentAsShort(xml, childElement);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the immediate child. Returns null if the child element was not found.
|
||||
/// </summary>
|
||||
@@ -856,6 +920,26 @@ namespace ICD.Common.Utils.Xml
|
||||
return ReadListFromXml(xml, rootElement, childElement, readChild);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the xml to a dictionary.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="rootElement"></param>
|
||||
/// <param name="childElement"></param>
|
||||
/// <param name="keyElement"></param>
|
||||
/// <param name="valueElement"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> ReadDictFromXml<TKey, TValue>(
|
||||
string xml, string rootElement, string childElement, string keyElement, string valueElement)
|
||||
{
|
||||
Func<string, TKey> readKey = IcdXmlConvert.DeserializeObject<TKey>;
|
||||
Func<string, TValue> readValue = IcdXmlConvert.DeserializeObject<TValue>;
|
||||
|
||||
return ReadDictFromXml(xml, rootElement, childElement, keyElement, valueElement, readKey, readValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls childElementCallback for each item in the list.
|
||||
/// </summary>
|
||||
@@ -876,6 +960,20 @@ namespace ICD.Common.Utils.Xml
|
||||
yield return readChild(child);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the xml to a list.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <param name="rootElement"></param>
|
||||
/// <param name="childElement"></param>
|
||||
public static IEnumerable<T> ReadListFromXml<T>(string xml, string rootElement, string childElement)
|
||||
{
|
||||
Func<string, T> readChild = IcdXmlConvert.DeserializeObject<T>;
|
||||
|
||||
return ReadListFromXml(xml, rootElement, childElement, readChild);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Write Content
|
||||
@@ -1000,36 +1098,7 @@ namespace ICD.Common.Utils.Xml
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given xml is valid.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool IsValidXml(string xml)
|
||||
{
|
||||
try
|
||||
{
|
||||
IcdXmlDocument document = new IcdXmlDocument();
|
||||
document.LoadXml(xml);
|
||||
return true;
|
||||
}
|
||||
catch (IcdXmlException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints the xml document.
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
[PublicAPI]
|
||||
public static void Print(string xml)
|
||||
{
|
||||
string result = Format(xml);
|
||||
IcdConsole.PrintLine(result);
|
||||
}
|
||||
#region Print
|
||||
|
||||
/// <summary>
|
||||
/// Formats the given xml string into a human readable structure with indentations.
|
||||
@@ -1048,12 +1117,12 @@ namespace ICD.Common.Utils.Xml
|
||||
IcdXmlDocument document = new IcdXmlDocument();
|
||||
document.LoadXml(xml);
|
||||
document.WriteContentTo(writer);
|
||||
|
||||
writer.Flush();
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user