Compare commits

..

37 Commits

Author SHA1 Message Date
Chris Cameron
15330d7dd0 chore: Updating changelog, incrementing patch version 2020-08-17 10:03:30 -04:00
Chris Cameron
34cfe8c7a3 fix: Workaround for logged XML format exceptions when failing to parse floats 2020-08-17 10:01:58 -04:00
Drew Tingen
7f306801b3 chore: Updating changelog, incremeting patch version 2020-07-29 10:01:43 -04:00
Austin Noska
51ec3dd8ff docs: Update changelog 2020-07-28 18:09:00 -04:00
Austin Noska
7cc8359284 fix: Check if any & all characters in a string is a digit instead of just all 2020-07-28 17:31:41 -04:00
Chris Cameron
62f54f1213 chore: Updating changelog, incrementing patch version 2020-05-27 15:56:22 -04:00
Drew Tingen
dd3c0f530b chore: Changelog 2020-05-27 11:28:12 -04:00
Drew Tingen
fc74865c5b feat: Use CrestronEnvironment.SystemInfo.SerialNumber to retrieve the serial number, instead of trying to convert TSID from console. 2020-05-27 11:25:14 -04:00
Chris Cameron
d90c60126e chore: Updating changelog, incrementing minor version 2020-04-30 13:02:14 -04:00
Drew Tingen
49d12d454f fix: Program and Processor utils actually return DateTimes for date properties 2020-04-30 12:58:23 -04:00
Chris Cameron
69eb4b3d34 chore: Updating changelog, incrementing patch version 2020-02-18 12:13:00 -05:00
Drew Tingen
8e5486e1ef chore: Changelog 2020-02-14 23:56:56 -05:00
Drew Tingen
ecf7e626f3 fix: IcdTimer fix issue that prevents OnElapsed callback from firing when Length is less than (or close to) Heartbeat Interval 2020-02-14 23:55:32 -05:00
Chris Cameron
d025946948 chore: Updating changelog, incrementing minor version 2020-01-23 12:46:06 -05:00
Chris Cameron
b74d2c9d60 fix: Adding PriorityQueue EnqueueRemove overload for backwards compat 2020-01-23 12:44:08 -05:00
Jack Kanarish
ac4c0eccc9 feat: add ability to select when de-duplication should queue at the end of the queue, or at the first occurance
# Conflicts:
#	ICD.Common.Utils/Collections/PriorityQueue.cs
2020-01-23 11:44:31 -05:00
Chris Cameron
55bf458a2b test: Fixing PriorityQueue unit tests 2020-01-06 10:28:03 -05:00
Chris Cameron
0a1f637b45 chore: Updating changelog, incrementing patch version 2019-10-29 14:52:36 -04:00
Chris Cameron
e0ace12ef9 Merge pull request #43 from Utils fix/SerialQueueFix
Fix/SerialQueueFix
2019-10-29 14:33:28 -04:00
Jack Kanarish
9f1541f843 chore: update changelog 2019-10-29 14:19:58 -04:00
Jack Kanarish
b9f5349055 fix: fix an issue where commands would collapse to the point of the last deleted command instead of the position in queue where the new command was going 2019-10-29 14:18:45 -04:00
Chris Cameron
5900f5974b chore: Updating changelog, incrementing patch version 2019-08-22 10:41:00 -04:00
Drew Tingen
81f7eb9c66 Merge branch 'fix/ordered-dict' of Common/Utils into MetLife_v5.4.3 2019-08-22 14:30:40 +00:00
Chris Cameron
440c1c62f1 fix: Fixed a bug with the IcdOrderedDict index setter that was creating additional values 2019-08-22 10:17:32 -04:00
Chris Cameron
e388f35efb Revert "fix: fix for logging deadlock, use mutexes, add logging for last message sent."
This reverts commit 7c238b9fef.
2019-08-15 10:56:34 -04:00
Jack Kanarish
89061b5cbf feat: add unit test for timer 2019-08-07 20:47:54 -04:00
Jack Kanarish
7c238b9fef fix: fix for logging deadlock, use mutexes, add logging for last message sent. 2019-07-31 16:22:05 -04:00
Chris Cameron
1be852685d chore: Updating changelog, incrementing minor version 2019-06-24 12:49:39 -04:00
Chris Cameron
6201184fab feat: IcdXmlException exposes LineNumber and LinePosition 2019-06-24 12:42:29 -04:00
Chris Cameron
b915401109 chore: Updating changelog, incrementing patch version 2019-06-14 16:52:56 -04:00
Austin Noska
3e3a4e33cb fix: SafeTimer Stopped now returns a SafeTimer with no due time and no repeat period 2019-06-14 16:51:36 -04:00
Chris Cameron
7666021925 chore: Updating changelog, incrementing minor version 2019-06-14 10:25:47 -04:00
Chris Cameron
7b6092c291 fix: Fixing issues with Remap methods, added unit tests 2019-06-13 17:35:03 -04:00
Chris Cameron
f7740aaea2 fix: Fixing overflow 2019-06-13 17:10:34 -04:00
Chris Cameron
c31b2b556b feat: Adding methods for remapping and clamping numeric values to ranges 2019-06-13 16:56:49 -04:00
Chris Cameron
8866a3e1e6 fix: Fixing tests, bad maths 2019-06-13 11:59:12 -04:00
Chris Cameron
e3273934a7 fix: Begin rewriting RangeAttribute 2019-06-12 23:42:59 -04:00
65 changed files with 1900 additions and 3101 deletions

View File

@@ -6,68 +6,49 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
## [9.5.0] - 2019-06-10
### Added
- Added Shim to read a list from xml with no root element
- Added a URI query builder
## [8.9.3] - 2020-08-17
### Changed
- Fixed JSON DateTime parsing in .Net Standard
- Fixed threading exception in TypeExtensions
- Fixes for platform-agnostic culture handling
## [9.4.0] - 2019-05-10
### Added
- Added extension method for peeking queues
- Added extension method for getting or adding a new item to a dictionary
- Added methods for serializing additional types, arrays and dictionaries to JSON
- AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization
- Added RemoveRange method to IcdHashSet
- Added IcdCultureInfo and CultureInfo database for localization
- Workaround for logged XML format exceptions when failing to parse floats
## [8.9.2] - 2020-07-28
### Changed
- IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost"
## [9.3.0] - 2019-04-16
### Added
- Added SPlusUtils with ConvertToInt method taking LowWord/HighWord ushorts
- Added JsonReader extension methods for reading DateTimes
- Added JsonReader extension methods for writing properties
- IcdStreamWriter exposes WriteLine(string)
- Added ProgramLogsPath to PathUtils
- StringExtensions - fixed an issue with IsNumeric where empty strings would return true
## [8.9.1] - 2020-05-27
### Changed
- Fixes for VC4 compatibility
- Fixed JSON DateTime parsing for timezone information
- Small reflection optimizations
## [9.2.0] - 2019-03-01
### Added
- Added Type IsAssignableTo extension shim
- Added constructor to BiDictionary to instantiate from an existing dict
- Changed ProcessorUtils to use CrestronEnvironment to retrive serial number - this fixes issues with new serial numbers that aren't deciaml TSIDs
## [8.9.0] - 2020-04-30
### Changed
- Fixed bug preventing deserialization of XML lists
- Crestron ConsoleResponse uses PrintLine instead of Print
- Use PrintLine instead of ConsoleResponse on Crestron server
## [9.1.0] - 2019-02-07
### Added
- Added SubscribeEvent shim for delegate callbacks
- Extension method for reading JSON token as a GUID
- Added ToStringJsonConverter
- ProgramUtils and ProcessorUtils return dates instead of strings for date properties
## [8.8.1] - 2020-02-18
### Changed
- Significantly reduced size of JSON serialized Types
- Small logging optimizations
- IcdTimer - fixed issue that prevented OnElapsed event from firing when Length is less than (or close to) Heartbeat Interval
## [9.0.0] - 2019-01-29
## [8.8.0] - 2020-01-23
### Added
- IcdConsole.OnConsolePrint event
- Added an overload to PriorityQueue for determing the de-duplication behaviour
## [8.7.2] - 2019-10-29
### Changed
- Better VC-4 support for IcdConsole
- JSON refactoring for simpler deserialization
- Fixed a bug with PriorityQueue de-duplication where a new command would be inserted in the wrong position
## [8.7.1] - 2019-08-22
### Changed
- Fixed a bug with the IcdOrderedDict index setter that was creating additional values
## [8.7.0] - 2019-06-24
### Added
- IcdXmlException exposes line number and position properties
## [8.6.1] - 2019-06-14
### Changed
- Fixed a bug where stopped timers on NetStandard would still have a periodic callback duration
## [8.6.0] - 2019-06-14
### Changed
- Overhaul of RangeAttribute remap methods to better avoid overflows
## [8.5.0] - 2019-06-06
### Added

View File

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

View File

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

View File

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

View File

@@ -133,8 +133,8 @@ namespace ICD.Common.Utils.Tests.Collections
};
Assert.AreEqual(1, dequeue[0]);
Assert.AreEqual(4, dequeue[1]);
Assert.AreEqual(3, dequeue[2]);
Assert.AreEqual(3, dequeue[1]);
Assert.AreEqual(4, dequeue[2]);
}
[Test]

View File

@@ -3,7 +3,6 @@ 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;
@@ -18,36 +17,6 @@ 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()
{
@@ -109,5 +78,53 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.IsTrue(deserialized.SequenceEqual(new[] {1, 2, 3, 4}));
}
[Test]
public void SerializeDictionaryTest()
{
Dictionary<int, string> dict = new Dictionary<int, string>
{
{1, "Item 1"},
{10, "Item 2"},
{15, "Item 3"}
};
JsonSerializer serializer = new JsonSerializer();
StringBuilder stringBuilder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(stringBuilder))
{
using (JsonWriter writer = new JsonTextWriter(stringWriter))
{
serializer.SerializeDictionary(writer, dict);
}
}
string json = stringBuilder.ToString();
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
}
[Test]
public void DeserializeDictionaryTest()
{
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
JsonSerializer serializer = new JsonSerializer();
Dictionary<int, string> deserialized;
using (StringReader stringReader = new StringReader(json))
{
using (JsonReader reader = new JsonTextReader(stringReader))
{
reader.Read();
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
}
}
Assert.AreEqual(3, deserialized.Count);
Assert.AreEqual("Item 1", deserialized[1]);
Assert.AreEqual("Item 2", deserialized[10]);
Assert.AreEqual("Item 3", deserialized[15]);
}
}
}

View File

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

View File

@@ -20,9 +20,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -63,15 +63,14 @@ namespace ICD.Common.Utils.Tests
#endregion
[TestCase("/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http:///", null, null, null, null, (ushort)0, null, "http", null)]
[TestCase("http://localhost:80/", null, "localhost", null, null, (ushort)80, null, "http", null)]
[TestCase("http://username@localhost/", null, "localhost", null, null, (ushort)0, null, "http", "username")]
[TestCase("http://localhost/", null, "localhost", "password", null, (ushort)0, null, "http", null)]
[TestCase("https://localhost/", null, "localhost", null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, "localhost", null, "test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/test", null, "localhost", null, "/test", (ushort)0, null, "http", null)]
[TestCase("http://localhost//test", null, "localhost", null, "//test", (ushort)0, null, "http", null)]
[TestCase("http://localhost/", null, null, null, null, (ushort)0, null, null, null)]
[TestCase("http://localhost:80/", null, null, null, null, (ushort)80, null, null, null)]
[TestCase("http://username@localhost/", null, null, null, null, (ushort)0, null, null, "username")]
[TestCase("http://localhost/", null, null, "password", null, (ushort)0, null, null, null)]
[TestCase("https://localhost/", null, null, null, null, (ushort)0, null, "https", null)]
[TestCase("http://localhost/test", null, null, null, "test", (ushort)0, null, null, null)]
[TestCase("http://localhost/test", null, null, null, "/test", (ushort)0, null, null, null)]
[TestCase("http://localhost//test", null, null, null, "//test", (ushort)0, null, null, null)]
public void ToStringTest(string expected, string fragment, string address, string password, string path, ushort port,
string query, string scheme, string userName)
{

View File

@@ -2,6 +2,7 @@
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
@@ -18,11 +19,7 @@ namespace ICD.Common.Utils.Tests.Json
[Test]
public void ParseDateTimeTest()
{
const string dataA = "2016-02-26T19:24:59";
const string dataB = "2019-04-01T12:41:15-04:00";
Assert.DoesNotThrow(() => JsonUtils.ParseDateTime(dataA));
Assert.DoesNotThrow(() => JsonUtils.ParseDateTime(dataB));
Assert.Inconclusive();
}
[Test]
@@ -144,6 +141,32 @@ namespace ICD.Common.Utils.Tests.Json
Assert.AreEqual("test message", messageName);
}
[Test]
public void DeserializeTypeTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token);
Assert.AreEqual(10, value);
}
[Test]
public void DeserializeTestSerializerTest()
{
const string json = "{\"test\":10}";
JObject root = JObject.Parse(json);
JToken token = root["test"];
int value = (int)JsonUtils.Deserialize(typeof(int), token, new JsonSerializer());
Assert.AreEqual(10, value);
}
public sealed class TestSerializable
{
private const string PROPERTY_NAME = "Test";

View File

@@ -27,6 +27,10 @@ namespace ICD.Common.Utils.Tests
[Test, UsedImplicitly]
public void MapRangeTest()
{
Assert.AreEqual(5, MathUtils.MapRange(-100, 100, 0, 10, 0));
Assert.AreEqual(7, MathUtils.MapRange(-100, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(-100, 100, 0, 10, 100));
Assert.AreEqual(0, MathUtils.MapRange(0, 100, 0, 10, 0));
Assert.AreEqual(5, MathUtils.MapRange(0, 100, 0, 10, 50));
Assert.AreEqual(10, MathUtils.MapRange(0, 100, 0, 10, 100));
@@ -36,7 +40,7 @@ namespace ICD.Common.Utils.Tests
Assert.AreEqual(100, MathUtils.MapRange(0, 10, 0, 100, 10));
}
[Test, UsedImplicitly]
[Test, UsedImplicitly]
public void GetRangesTest()
{
IEnumerable<int> values = new [] { 1, 3, 5, 6, 7, 8, 9, 10, 12 };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Collections
{
@@ -329,18 +328,6 @@ namespace ICD.Common.Utils.Collections
return m_Dict.Remove(item);
}
/// <summary>
/// Removes each of the items in the sequence from the collection.
/// </summary>
/// <param name="items"></param>
public void RemoveRange(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
m_Dict.RemoveAll(items);
}
#endregion
#region IEnumerable<T>

View File

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

View File

@@ -84,6 +84,20 @@ namespace ICD.Common.Utils.Collections
m_Count++;
}
/// <summary>
/// Adds the item to the queue with the given priority at the given index.
/// </summary>
/// <param name="item"></param>
/// <param name="priority"></param>
/// <param name="position"></param>
[PublicAPI]
public void Enqueue([CanBeNull] T item, int priority, int position)
{
m_PriorityToQueue.GetOrAddNew(priority, ()=> new List<T>())
.Insert(position, item);
m_Count++;
}
/// <summary>
/// Enqueues the item at the beginning of the queue.
/// </summary>
@@ -106,8 +120,8 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
@@ -122,19 +136,38 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
[PublicAPI]
public void EnqueueRemove(T item, Func<T, bool> remove, int priority)
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority)
{
if (remove == null)
throw new ArgumentNullException("remove");
bool inserted = false;
EnqueueRemove(item, remove, priority, false);
}
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
/// <param name="deDuplicateToEndOfQueue"></param>
[PublicAPI]
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority, bool deDuplicateToEndOfQueue)
{
if (remove == null)
throw new ArgumentNullException("remove");
int lowestMatchingPriority = int.MaxValue;
int? firstMatchingIndex = null;
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue.ToArray())
{
@@ -144,8 +177,11 @@ namespace ICD.Common.Utils.Collections
.Reverse()
.ToArray();
if (removeIndices.Length == 0)
continue;
if (removeIndices.Any() && kvp.Key < lowestMatchingPriority )
{
lowestMatchingPriority = kvp.Key;
firstMatchingIndex = removeIndices.Last();
}
foreach (int removeIndex in removeIndices)
{
@@ -153,26 +189,20 @@ namespace ICD.Common.Utils.Collections
m_Count--;
}
if (!inserted)
{
int insertIndex = removeIndices[0];
if (insertIndex >= kvp.Value.Count)
kvp.Value.Add(item);
else
kvp.Value.Insert(insertIndex, item);
m_Count++;
inserted = true;
}
if (kvp.Value.Count == 0)
m_PriorityToQueue.Remove(kvp.Key);
}
if (!inserted)
if(deDuplicateToEndOfQueue)
Enqueue(item, priority);
else
{
if(firstMatchingIndex == null)
Enqueue(item, lowestMatchingPriority);
else
Enqueue(item, lowestMatchingPriority, firstMatchingIndex.Value);
}
}
/// <summary>

View File

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

View File

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

Binary file not shown.

View File

@@ -19,9 +19,6 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
if (keys == null)
throw new ArgumentNullException("keys");
foreach (TKey key in keys)
extends.Remove(key);
}
@@ -115,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)
@@ -139,22 +137,28 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="valueFunc"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
where TValue : new()
public static TValue GetOrAddNew<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] TKey key,
[NotNull] Func<TValue> valueFunc)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (valueFunc == null)
throw new ArgumentNullException("valueFunc");
TValue value;
if (!extends.TryGetValue(key, out value))
{
value = ReflectionUtils.CreateInstance<TValue>();
value = valueFunc();
extends.Add(key, value);
}

View File

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

View File

@@ -1,217 +0,0 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Json;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with JSON.
/// </summary>
public static class JsonReaderExtensions
{
/// <summary>
/// Reads the current token in the reader and deserializes to the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static T ReadAsObject<T>(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
JsonSerializer serializer = 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="serializer"></param>
/// <returns></returns>
public static T ReadAsObject<T>(this JsonReader extends, JsonSerializer serializer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
return serializer.Deserialize<T>(extends);
}
/// <summary>
/// Reads through the current object token and calls the callback for each property value.
/// </summary>
/// <param name="extends"></param>
/// <param name="serializer"></param>
/// <param name="readPropertyValue"></param>
public static void ReadObject(this JsonReader extends, JsonSerializer serializer,
Action<string, JsonReader, JsonSerializer> readPropertyValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (serializer == null)
throw new ArgumentNullException("serializer");
if (readPropertyValue == null)
throw new ArgumentNullException("readPropertyValue");
if (extends.TokenType == JsonToken.Null)
return;
if (extends.TokenType != JsonToken.StartObject)
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, extends.TokenType));
while (extends.Read())
{
if (extends.TokenType == JsonToken.EndObject)
break;
// Get the property
if (extends.TokenType != JsonToken.PropertyName)
continue;
string property = (string)extends.Value;
// Read into the value
extends.Read();
readPropertyValue(property, extends, serializer);
}
}
/// <summary>
/// Gets the current value as a Type.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Type GetValueAsType(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetValueAsString();
return Type.GetType(value);
}
/// <summary>
/// Gets the current value as an unsigned integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static uint GetValueAsUInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (uint)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an integer.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int GetValueAsInt(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (int)(long)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as a string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetValueAsString(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Value == null ? null : extends.Value.ToString();
}
/// <summary>
/// Gets the current value as a bool.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetValueAsBool(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Boolean)
return (bool)extends.Value;
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
throw new InvalidCastException(message);
}
/// <summary>
/// Gets the current value as an enum.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T GetValueAsEnum<T>(this JsonReader extends)
where T : struct, IConvertible
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String)
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
/// <summary>
/// Gets the current value as a guid.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Guid GetValueAsGuid(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string stringValue = extends.GetValueAsString();
return new Guid(stringValue);
}
/// <summary>
/// Gets the current value as a date.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static DateTime GetValueAsDateTime(this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string stringValue = extends.GetValueAsString();
return JsonUtils.ParseDateTime(stringValue);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -205,7 +205,7 @@ namespace ICD.Common.Utils.Extensions
if (extends == null)
throw new ArgumentNullException("extends");
return extends.All(char.IsDigit);
return extends.AnyAndAll(char.IsDigit);
}
/// <summary>

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -78,6 +78,7 @@
<Compile Include="Attributes\IIcdAttribute.cs" />
<Compile Include="Attributes\RangeAttribute.cs" />
<Compile Include="Collections\BiDictionary.cs" />
<Compile Include="Collections\AsyncEventQueue.cs" />
<Compile Include="Collections\IcdOrderedDictionary.cs" />
<Compile Include="Collections\PriorityQueue.cs" />
<Compile Include="Collections\RateLimitedEventQueue.cs" />
@@ -102,29 +103,22 @@
<Compile Include="EventArguments\StringEventArgs.cs" />
<Compile Include="EventArguments\UShortEventArgs.cs" />
<Compile Include="EventArguments\XmlRecursionEventArgs.cs" />
<None Include="CultureInfo.sqlite">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ObfuscationSettings.cs" />
<Compile Include="Extensions\BoolExtensions.cs" />
<Compile Include="Extensions\ByteExtensions.cs" />
<Compile Include="Extensions\DayOfWeekExtensions.cs" />
<Compile Include="Extensions\JsonSerializerExtensions.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="Globalization\IcdCultureInfo.cs" />
<Compile Include="GuidUtils.cs" />
<Compile Include="IcdUriBuilder.cs" />
<Compile Include="IO\Compression\IcdZipEntry.cs" />
<Compile Include="IO\IcdBinaryReader.cs" />
<Compile Include="IO\eSeekOrigin.cs" />
<Compile Include="IO\IcdStreamWriter.cs" />
<Compile Include="Json\ToStringJsonConverter.cs" />
<Compile Include="ProcessorUtils.SimplSharp.cs" />
<Compile Include="ProcessorUtils.Standard.cs" />
<Compile Include="ProgramUtils.SimplSharp.cs" />
@@ -162,7 +156,7 @@
<Compile Include="Extensions\EnumerableExtensions.cs" />
<Compile Include="Extensions\EnumExtensions.cs" />
<Compile Include="Extensions\EventHandlerExtensions.cs" />
<Compile Include="Extensions\JsonReaderExtensions.cs" />
<Compile Include="Extensions\JsonExtensions.cs" />
<Compile Include="Extensions\QueueExtensions.cs" />
<Compile Include="Extensions\ReflectionExtensions.cs" />
<Compile Include="Extensions\StringBuilderExtensions.cs" />
@@ -193,7 +187,6 @@
<Compile Include="SafeCriticalSection.SimplSharp.cs" />
<Compile Include="SafeCriticalSection.Standard.cs" />
<Compile Include="SafeMutex.cs" />
<Compile Include="SPlusUtils.cs" />
<Compile Include="Sqlite\eDbType.cs" />
<Compile Include="Sqlite\IcdDbDataReader.cs" />
<Compile Include="Sqlite\IcdSqliteCommand.cs" />
@@ -211,7 +204,6 @@
<Compile Include="Timers\Repeater.cs" />
<Compile Include="Timers\SafeTimer.cs" />
<Compile Include="TryUtils.cs" />
<Compile Include="UriQueryBuilder.cs" />
<Compile Include="UriUtils.cs" />
<Compile Include="Xml\AbstractGenericXmlConverter.cs" />
<Compile Include="Xml\AbstractXmlConverter.cs" />

View File

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

View File

@@ -1,8 +1,6 @@
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
@@ -20,8 +18,6 @@ namespace ICD.Common.Utils
Administrator = 2
}
public static event EventHandler<StringEventArgs> OnConsolePrint;
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
@@ -45,34 +41,26 @@ namespace ICD.Common.Utils
message = string.Format(message, args);
#if SIMPLSHARP
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpPro)
try
{
try
{
CrestronConsole.ConsoleCommandResponse(message);
}
catch (NotSupportedException)
{
PrintLine(message);
}
return;
CrestronConsole.ConsoleCommandResponse(message);
}
catch (NotSupportedException)
{
Print(message);
}
#else
Print(message);
#endif
PrintLine(message);
}
public static void PrintLine(string message)
{
#if SIMPLSHARP
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
CrestronConsole.PrintLine(message);
CrestronConsole.PrintLine(message);
#else
Console.WriteLine(message);
#endif
OnConsolePrint.Raise(null, new StringEventArgs(message + IcdEnvironment.NewLine));
}
public static void PrintLine(string message, params object[] args)
@@ -102,12 +90,10 @@ namespace ICD.Common.Utils
public static void Print(string message)
{
#if SIMPLSHARP
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
CrestronConsole.Print(message);
CrestronConsole.Print(message);
#else
Console.Write(message);
#endif
OnConsolePrint.Raise(null, new StringEventArgs(message));
}
public static void Print(string message, params object[] args)

View File

@@ -66,7 +66,7 @@ namespace ICD.Common.Utils
/// Constructor.
/// </summary>
public IcdUriBuilder()
: this(new Uri("http://localhost/"))
: this((Uri)null)
{
}
@@ -86,7 +86,7 @@ namespace ICD.Common.Utils
public IcdUriBuilder(Uri uri)
{
if (uri == null)
throw new ArgumentNullException("uri");
return;
if (!uri.IsAbsoluteUri)
uri = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri);
@@ -107,20 +107,20 @@ namespace ICD.Common.Utils
/// <returns></returns>
public override string ToString()
{
// URI = [scheme://][authority]path[?query][#fragment]
// URI = scheme:[//authority]path[?query][#fragment]
// authority = [userinfo@]host[:port]
// userinfo = username[:password]
StringBuilder builder = new StringBuilder();
// Scheme
if (!string.IsNullOrEmpty(Scheme))
{
builder.Append(Scheme);
builder.Append("://");
}
string scheme = string.IsNullOrEmpty(Scheme) ? Uri.UriSchemeHttp : Scheme;
builder.Append(scheme);
builder.Append(':');
// Authority
builder.Append("//");
if (!string.IsNullOrEmpty(UserName))
{
builder.Append(UserName);
@@ -134,7 +134,8 @@ namespace ICD.Common.Utils
builder.Append('@');
}
builder.Append(Host);
string host = string.IsNullOrEmpty(Host) ? "localhost" : Host;
builder.Append(host);
if (Port != 0)
{

View File

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

View File

@@ -18,6 +18,28 @@ 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 data as a DateTime value.
/// </summary>
@@ -71,6 +93,31 @@ 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>
@@ -193,22 +240,6 @@ 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.
@@ -292,5 +323,44 @@ namespace ICD.Common.Utils.Json
},
json);
}
/// <summary>
/// Deserializes the given token based on the known type.
/// </summary>
/// <param name="type"></param>
/// <param name="token"></param>
/// <returns></returns>
public static object Deserialize(Type type, JToken token)
{
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
return Deserialize(type, token, new JsonSerializer());
}
/// <summary>
/// Deserializes the given token based on the known type.
/// </summary>
/// <param name="type"></param>
/// <param name="token"></param>
/// <param name="serializer"></param>
/// <returns></returns>
public static object Deserialize(Type type, JToken token, JsonSerializer serializer)
{
if (type == null)
throw new ArgumentNullException("type");
if (token == null)
throw new ArgumentNullException("token");
if (serializer == null)
throw new ArgumentNullException("serializer");
using (JTokenReader jsonReader = new JTokenReader(token))
return serializer.Deserialize(jsonReader, type);
}
}
}

View File

@@ -1,89 +0,0 @@
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;
}
}
}

View File

@@ -138,42 +138,6 @@ namespace ICD.Common.Utils
return (ushort)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static ulong MapRange(ulong inputStart, ulong inputEnd, ulong outputStart, ulong outputEnd, ulong value)
{
if (inputStart.Equals(inputEnd))
throw new DivideByZeroException();
ulong slope = (outputEnd - outputStart) / (inputEnd - inputStart);
return outputStart + slope * (value - inputStart);
}
/// <summary>
/// Returns the value after the input range has been mapped to a new range
/// </summary>
/// <param name="inputStart">Input start.</param>
/// <param name="inputEnd">Input end.</param>
/// <param name="outputStart">Output start.</param>
/// <param name="outputEnd">Output end.</param>
/// <param name="value">Value.</param>
/// <returns>The newly mapped value</returns>
public static long MapRange(long inputStart, long inputEnd, long outputStart, long outputEnd, long value)
{
if (inputStart.Equals(inputEnd))
throw new DivideByZeroException();
long slope = (outputEnd - outputStart) / (inputEnd - inputStart);
return outputStart + slope * (value - inputStart);
}
/// <summary>
/// Maps the date in the given range to the float range 0.0f to 1.0f.
/// 0.5f - The date is half way between the end points.

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
@@ -58,29 +57,23 @@ namespace ICD.Common.Utils
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramConfigPath { get { return Join(RootConfigPath, ProgramConfigDirectory); } }
public static string ProgramConfigPath
{
get
{
return Join(RootConfigPath, ProgramConfigDirectory);
}
}
/// <summary>
/// Returns the name of the program config directory.
/// </summary>
[PublicAPI]
public static string ProgramConfigDirectory
{
get
{
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
return "ProgramConfig";
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
return "ProgramConfig";
default:
throw new ArgumentOutOfRangeException();
}
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
}
}
@@ -105,37 +98,6 @@ namespace ICD.Common.Utils
[PublicAPI]
public static string ProgramLibPath { get { return Join(ProgramConfigPath, "Lib"); } }
/// <summary>
/// Returns the absolute path to the logs directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramLogsPath
{
get
{
string directoryName;
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
directoryName = string.Format("Program{0:D2}Logs", ProgramUtils.ProgramNumber);
break;
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
directoryName = "ProgramLogs";
break;
default:
throw new ArgumentOutOfRangeException();
}
return Join(RootConfigPath, directoryName);
}
}
#endregion
#region Methods

View File

@@ -1,6 +1,8 @@
using ICD.Common.Utils.Services;
#if SIMPLSHARP
using System.Globalization;
using Crestron.SimplSharp;
using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using System;
using System.Text.RegularExpressions;
using ICD.Common.Properties;
@@ -55,15 +57,11 @@ namespace ICD.Common.Utils
{
get
{
string versionResult = VersionResult;
if (!String.IsNullOrEmpty(versionResult))
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(versionResult);
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return match.Groups["model"].Value;
}
if (match.Success)
return match.Groups["model"].Value;
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model name from \"{0}\"", VersionResult);
@@ -79,15 +77,11 @@ namespace ICD.Common.Utils
{
get
{
string versionResult = VersionResult;
if (!String.IsNullOrEmpty(versionResult))
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return new Version(match.Groups["version"].Value);
}
if (match.Success)
return new Version(match.Groups["version"].Value);
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version from \"{0}\"", VersionResult);
@@ -99,7 +93,7 @@ namespace ICD.Common.Utils
/// Gets the date that the firmware was updated.
/// </summary>
[PublicAPI]
public static string ModelVersionDate
public static DateTime ModelVersionDate
{
get
{
@@ -107,12 +101,12 @@ namespace ICD.Common.Utils
Match match = regex.Match(VersionResult);
if (match.Success)
return match.Groups["date"].Value;
return DateTime.ParseExact(match.Groups["date"].Value, "MMM dd yyyy", CultureInfo.InvariantCulture).ToUniversalTime();
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version date from \"{0}\"", VersionResult);
return string.Empty;
return DateTime.MinValue;
}
}
@@ -124,19 +118,7 @@ namespace ICD.Common.Utils
{
get
{
Regex regex = new Regex(VER_REGEX);
Match match = regex.Match(VersionResult);
if (!match.Success)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get serial number from \"{0}\"", VersionResult);
return string.Empty;
}
int decValue = int.Parse(match.Groups["serial"].Value, System.Globalization.NumberStyles.HexNumber);
return decValue.ToString();
return CrestronEnvironment.SystemInfo.SerialNumber;
}
}

View File

@@ -31,12 +31,12 @@ namespace ICD.Common.Utils
/// Gets the date that the firmware was updated.
/// </summary>
[PublicAPI]
public static string ModelVersionDate
public static DateTime ModelVersionDate
{
get
{
// TODO
return null;
return DateTime.MinValue;
}
}

View File

@@ -1,4 +1,5 @@
using ICD.Common.Utils.Services;
using ICD.Common.Utils.IO;
using ICD.Common.Utils.Services;
using ICD.Common.Utils.Services.Logging;
#if SIMPLSHARP
using Crestron.SimplSharp;
@@ -40,7 +41,16 @@ namespace ICD.Common.Utils
/// Gets the compile date of the program.
/// </summary>
[PublicAPI]
public static string CompiledDate { get { return ProgComments.GetDefault(COMPILED_ON_KEY, null); } }
public static DateTime CompiledDate
{
get
{
string dateString;
return ProgComments.TryGetValue(COMPILED_ON_KEY, out dateString)
? DateTime.Parse(dateString).ToUniversalTime()
: DateTime.MinValue;
}
}
/// <summary>
/// Gets the compiler revision version.
@@ -86,6 +96,16 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Returns the date and time the program was installed.
/// </summary>
/// <returns></returns>
[PublicAPI]
public static DateTime ProgramInstallDate
{
get { return IcdFile.GetCreationTime(PathUtils.Join(PathUtils.ProgramPath, ProgramFile)).ToUniversalTime(); }
}
/// <summary>
/// Parses the prog comments and pulls program information.
/// </summary>

View File

@@ -18,11 +18,11 @@ namespace ICD.Common.Utils
/// Gets the compile date of the program.
/// </summary>
[PublicAPI]
public static string CompiledDate
public static DateTime CompiledDate
{
get
{
return IcdFile.GetLastWriteTime(Assembly.GetEntryAssembly().Location).ToString();
return IcdFile.GetLastWriteTime(Assembly.GetEntryAssembly().Location);
}
}

View File

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

View File

@@ -3,7 +3,6 @@ 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
{
@@ -98,23 +97,23 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Returns true if there is a path from the given root to the given destination node.
/// Returns true if there is a path from the given root to the given child node.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="root"></param>
/// <param name="destination"></param>
/// <param name="child"></param>
/// <param name="getChildren"></param>
/// <returns></returns>
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
public static bool BreadthFirstSearch<T>(T root, T child, Func<T, IEnumerable<T>> getChildren)
{
if (getChildren == null)
throw new ArgumentNullException("getChildren");
return BreadthFirstSearch(root, destination, getChildren, EqualityComparer<T>.Default);
return BreadthFirstSearchPath(root, child, getChildren) != null;
}
/// <summary>
/// Returns true if there is a path from the given root to the given destination node.
/// Returns true if there is a path from the given root to the given child node.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="root"></param>
@@ -160,9 +159,9 @@ namespace ICD.Common.Utils
Queue<T> process = new Queue<T>();
process.Enqueue(root);
T current;
while (process.Dequeue(out current))
while (process.Count > 0)
{
T current = process.Dequeue();
yield return current;
foreach (T child in getChildren(current))
@@ -215,9 +214,10 @@ namespace ICD.Common.Utils
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
T current;
while (queue.Dequeue(out current))
while (queue.Count > 0)
{
T current = queue.Dequeue();
foreach (T node in getChildren(current))
{
if (nodeParents.ContainsKey(node))

View File

@@ -220,9 +220,6 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
if (parameters.Length == 0)
return Activator.CreateInstance(type);
ConstructorInfo constructor = GetConstructor(type, parameters);
try
@@ -340,9 +337,8 @@ namespace ICD.Common.Utils
if (valueType.IsIntegerNumeric())
return Enum.ToObject(type, value);
string valueAsString = value as string;
if (valueAsString != null)
return Enum.Parse(type, valueAsString, false);
if (value is string)
return Enum.Parse(type, value as string, false);
}
return Convert.ChangeType(value, type, null);
@@ -356,56 +352,12 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Subscribes to the event on the given instance using the event handler.
/// Subscribes to the event on the given instance using the handler and callback 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="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>
/// <param name="handler">The instance with the callback MethodInfo. Null for static types.</param>
/// <param name="callback">The MethodInfo for the callback method.</param>
/// <returns></returns>
[NotNull]
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, object handler, MethodInfo callback)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -118,6 +118,7 @@ namespace ICD.Common.Utils.Timers
Length = length;
m_Stopwatch.Reset();
m_LastHeartbeatMilliseconds = 0;
m_Stopwatch.Start();
RaiseOnIsRunningChanged();

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using ICD.Common.Utils.IO;
#if SIMPLSHARP
@@ -71,12 +72,7 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("type");
using (IcdXmlReader reader = new IcdXmlReader(xml))
{
if (reader.ReadToNextElement())
return DeserializeObject(type, reader);
throw new FormatException("Expected element in XML");
}
return DeserializeObject(type, reader);
}
/// <summary>
@@ -212,127 +208,37 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("type");
if (type == typeof(bool))
return ToBool(value);
return bool.Parse(value);
if (type == typeof(byte))
return ToByte(value);
return byte.Parse(value);
if (type == typeof(decimal))
return ToDecimal(value);
return decimal.Parse(value);
if (type == typeof(char))
return ToChar(value);
return value.Single();
if (type == typeof(double))
return ToDouble(value);
return double.Parse(value);
if (type == typeof(Guid))
return ToGuid(value);
return new Guid(value);
if (type == typeof(float))
return ToSingle(value);
return float.Parse(value);
if (type == typeof(int))
return ToInt32(value);
return int.Parse((value));
if (type == typeof(long))
return ToInt64(value);
return long.Parse(value);
if (type == typeof(sbyte))
return ToSByte(value);
return sbyte.Parse(value);
if (type == typeof(short))
return ToInt16(value);
return short.Parse(value);
if (type == typeof(TimeSpan))
return ToTimeSpan(value);
return TimeSpan.Parse(value);
if (type == typeof(uint))
return ToUInt32(value);
return uint.Parse(value);
if (type == typeof(ulong))
return ToUInt64(value);
return ulong.Parse(value);
if (type == typeof(ushort))
return ToUInt16(value);
return ushort.Parse(value);
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
}
public static bool ToBool(string data)
{
return XmlConvert.ToBoolean(data);
}
public static byte ToByte(string data)
{
return XmlConvert.ToByte(data);
}
public static char ToChar(string data)
{
return XmlConvert.ToChar(data);
}
public static DateTime ToDateTime(string data, string format)
{
return XmlConvert.ToDateTime(data, format);
}
public static DateTime ToDateTime(string data, string[] formats)
{
return XmlConvert.ToDateTime(data, formats);
}
public static DateTime ToDateTime(string data, XmlDateTimeSerializationMode dateTimeOption)
{
return XmlConvert.ToDateTime(data, dateTimeOption);
}
public static decimal ToDecimal(string data)
{
return XmlConvert.ToDecimal(data);
}
public static double ToDouble(string data)
{
return XmlConvert.ToDouble(data);
}
public static Guid ToGuid(string data)
{
return XmlConvert.ToGuid(data);
}
public static short ToInt16(string data)
{
return XmlConvert.ToInt16(data);
}
public static int ToInt32(string data)
{
return XmlConvert.ToInt32(data);
}
public static long ToInt64(string data)
{
return XmlConvert.ToInt64(data);
}
public static sbyte ToSByte(string data)
{
return XmlConvert.ToSByte(data);
}
public static float ToSingle(string data)
{
return XmlConvert.ToSingle(data);
}
public static TimeSpan ToTimeSpan(string data)
{
return XmlConvert.ToTimeSpan(data);
}
public static ushort ToUInt16(string data)
{
return XmlConvert.ToUInt16(data);
}
public static uint ToUInt32(string data)
{
return XmlConvert.ToUInt32(data);
}
public static ulong ToUInt64(string data)
{
return XmlConvert.ToUInt64(data);
}
}
}

View File

@@ -9,8 +9,12 @@ namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlException : Exception
{
private int m_LineNumber;
private int m_LinePosition;
private readonly int m_LineNumber;
private readonly int m_LinePosition;
public int LineNumber { get { return m_LineNumber; } }
public int LinePosition { get { return m_LinePosition; } }
/// <summary>
/// Constructor.

View File

@@ -177,26 +177,16 @@ namespace ICD.Common.Utils.Xml
public long ReadElementContentAsLong()
{
try
{
return m_Reader.ReadElementContentAsLong();
}
catch (XmlException e)
{
throw new IcdXmlException(e);
}
// ReadElementContentAsLong() logs and throws...
string value = ReadElementContentAsString();
return long.Parse(value);
}
public float ReadElementContentAsFloat()
{
try
{
return m_Reader.ReadElementContentAsFloat();
}
catch (XmlException e)
{
throw new IcdXmlException(e);
}
// ReadElementContentAsFloat() logs and throws...
string value = ReadElementContentAsString();
return float.Parse(value);
}
public bool ReadElementContentAsBoolean()

View File

@@ -349,7 +349,7 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return IcdXmlConvert.ToUInt32(content);
return uint.Parse(content);
}
/// <summary>
@@ -364,7 +364,7 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return IcdXmlConvert.ToInt32(content);
return int.Parse(content);
}
/// <summary>
@@ -379,7 +379,7 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return IcdXmlConvert.ToUInt16(content);
return ushort.Parse(content);
}
/// <summary>
@@ -394,33 +394,7 @@ namespace ICD.Common.Utils.Xml
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return IcdXmlConvert.ToInt16(content);
}
/// <summary>
/// Parses the element content as a short.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static TimeSpan ReadElementContentAsTimeSpan(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
try
{
// 00:00:00 format
return TimeSpan.Parse(content);
}
catch (FormatException)
{
}
// PT0S format
return IcdXmlConvert.ToTimeSpan(content);
return short.Parse(content);
}
/// <summary>

View File

@@ -458,19 +458,6 @@ namespace ICD.Common.Utils.Xml
return reader.ReadElementContentAsByte();
}
/// <summary>
/// Gets the content of an immediate child.
/// </summary>
/// <param name="xml"></param>
/// <param name="childElement"></param>
/// <returns></returns>
[PublicAPI]
public static TimeSpan? ReadChildElementContentAsTimeSpan(string xml, string childElement)
{
using (IcdXmlReader reader = GetChildElement(xml, childElement))
return reader.ReadElementContentAsTimeSpan();
}
/// <summary>
/// Gets the content of an immediate child.
/// </summary>
@@ -676,25 +663,6 @@ 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 TimeSpan? TryReadChildElementContentAsTimeSpan(string xml, string childElement)
{
try
{
return ReadChildElementContentAsTimeSpan(xml, childElement);
}
catch (FormatException)
{
return null;
}
}
/// <summary>
/// Gets the content of the immediate child. Returns default if the child element could not be parsed.
/// </summary>
@@ -972,22 +940,6 @@ namespace ICD.Common.Utils.Xml
return ReadDictFromXml(xml, rootElement, childElement, keyElement, valueElement, readKey, readValue);
}
/// <summary>
/// Calls childElementCallback for each item in the list.
/// </summary>
/// <param name="xml"></param>
/// <param name="rootElement"></param>
/// <param name="childElement"></param>
/// <param name="readChild"></param>
public static IEnumerable<T> ReadListFromXml<T>(string xml, string childElement, Func<string, T> readChild)
{
if (readChild == null)
throw new ArgumentNullException("readChild");
foreach (string child in GetChildElementsAsString(xml, childElement))
yield return readChild(child);
}
/// <summary>
/// Calls childElementCallback for each item in the list.
/// </summary>
@@ -1004,22 +956,10 @@ namespace ICD.Common.Utils.Xml
if (!TryGetChildElementAsString(xml, rootElement, out xml))
yield break;
foreach (T child in ReadListFromXml(xml, childElement, readChild))
yield return child;
foreach (string child in GetChildElementsAsString(xml, childElement))
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 childElement)
{
Func<string, T> readChild = IcdXmlConvert.DeserializeObject<T>;
return ReadListFromXml(xml, childElement, readChild);
}
/// <summary>
/// Deserializes the xml to a list.