Created S# .sln and moved project to src folder

This commit is contained in:
jeff.thompson
2017-06-21 22:41:54 -04:00
commit 52948a6e7e
93 changed files with 10647 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
using System;
namespace ICD.Common.Attributes
{
/// <summary>
/// AbstractIcdAttribute is the base class for all ICD attributes.
/// It provides a global cache for looking up symbols via an attribute type.
/// </summary>
public abstract class AbstractIcdAttribute : Attribute
{
private readonly int m_HashCode;
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
protected AbstractIcdAttribute()
{
// Duplicate attributes (E.g. [A, A]) are considered to be the same instance by reflection.
// We get around this by using a GUID for the hash code.
m_HashCode = Guid.NewGuid().GetHashCode();
}
#endregion
#region Methods
/// <summary>
/// Gets the hash code for the instance.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return m_HashCode;
}
#endregion
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace ICD.Common.Attributes
{
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class KrangPluginAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,38 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.Attributes.Properties
{
/// <summary>
/// Provides information on a settings property.
/// </summary>
[PublicAPI]
public sealed class SettingsProperty : Attribute
{
public enum ePropertyType
{
[PublicAPI] Default,
[PublicAPI] PortId,
[PublicAPI] DeviceId,
[PublicAPI] Ipid,
[PublicAPI] Enum
}
private readonly ePropertyType m_PropertyType;
/// <summary>
/// Gets the property type.
/// </summary>
[PublicAPI]
public ePropertyType PropertyType { get { return m_PropertyType; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="propertyType"></param>
public SettingsProperty(ePropertyType propertyType)
{
m_PropertyType = propertyType;
}
}
}

View File

@@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Properties;
using ICD.Common.Utils;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Attributes.Rpc
{
/// <summary>
/// Represents a method that can be called by the server via RPC.
/// </summary>
[PublicAPI]
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public sealed class RpcAttribute : AbstractIcdAttribute
{
private static readonly Dictionary<Type, Dictionary<string, IcdHashSet<MethodInfo>>> s_MethodCache;
private static readonly Dictionary<Type, Dictionary<string, IcdHashSet<PropertyInfo>>> s_PropertyCache;
private static readonly SafeCriticalSection s_MethodCacheSection;
private static readonly SafeCriticalSection s_PropertyCacheSection;
private readonly string m_Key;
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
static RpcAttribute()
{
s_MethodCache = new Dictionary<Type, Dictionary<string, IcdHashSet<MethodInfo>>>();
s_PropertyCache = new Dictionary<Type, Dictionary<string, IcdHashSet<PropertyInfo>>>();
s_MethodCacheSection = new SafeCriticalSection();
s_PropertyCacheSection = new SafeCriticalSection();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="key"></param>
public RpcAttribute(string key)
{
m_Key = key;
}
#endregion
#region Methods
/// <summary>
/// Gets the method on the client with the given key, matching the parameter types.
/// </summary>
/// <param name="client"></param>
/// <param name="key"></param>
/// <param name="parameters"></param>
/// <returns></returns>
[CanBeNull]
public static MethodInfo GetMethod(object client, string key, IEnumerable<object> parameters)
{
return GetMethods(client, key).FirstOrDefault(m => ReflectionUtils.MatchesMethodParameters(m, parameters));
}
/// <summary>
/// Gets the property on the client with the given key, matching the parameter type.
/// </summary>
/// <param name="client"></param>
/// <param name="key"></param>
/// <param name="parameter"></param>
/// <returns></returns>
[CanBeNull]
public static PropertyInfo GetProperty(object client, string key, object parameter)
{
return GetProperties(client, key).FirstOrDefault(p => ReflectionUtils.MatchesPropertyParameter(p, parameter));
}
#endregion
#region Private Methods
/// <summary>
/// Returns the methods on the client with the given key.
/// </summary>
/// <param name="client"></param>
/// <param name="key"></param>
/// <returns></returns>
private static IEnumerable<MethodInfo> GetMethods(object client, string key)
{
s_MethodCacheSection.Enter();
try
{
Type clientType = client.GetType();
// Cache the methods for the key so subsequent calls are faster.
if (!s_MethodCache.ContainsKey(clientType))
s_MethodCache[clientType] = new Dictionary<string, IcdHashSet<MethodInfo>>();
if (!s_MethodCache[clientType].ContainsKey(key))
{
s_MethodCache[clientType][key] =
clientType
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetMethods(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Where(m => m.GetCustomAttributes<RpcAttribute>(true)
.Any(a => a.m_Key == key))
.ToHashSet();
}
return s_MethodCache[clientType][key];
}
finally
{
s_MethodCacheSection.Leave();
}
}
/// <summary>
/// Returns the properties on the client with the given key.
/// </summary>
/// <param name="client"></param>
/// <param name="key"></param>
/// <returns></returns>
private static IEnumerable<PropertyInfo> GetProperties(object client, string key)
{
s_PropertyCacheSection.Enter();
try
{
Type clientType = client.GetType();
// Cache the properties for the key so subsequent calls are faster.
if (!s_PropertyCache.ContainsKey(clientType))
s_PropertyCache[clientType] = new Dictionary<string, IcdHashSet<PropertyInfo>>();
if (!s_PropertyCache[clientType].ContainsKey(key))
{
s_PropertyCache[clientType][key] =
clientType
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetProperties(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Where(p => p.CanWrite && p.GetCustomAttributes<RpcAttribute>(true)
.Any(a => a.m_Key == key))
.ToHashSet();
}
return s_PropertyCache[clientType][key];
}
finally
{
s_PropertyCacheSection.Leave();
}
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
namespace ICD.Common.EventArguments
{
public sealed class BoolEventArgs : GenericEventArgs<bool>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public BoolEventArgs(bool data) : base(data)
{
}
}
}

View File

@@ -0,0 +1,12 @@
using ICD.Common.Properties;
namespace ICD.Common.EventArguments
{
[PublicAPI]
public sealed class CharEventArgs : GenericEventArgs<char>
{
public CharEventArgs(char value) : base(value)
{
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace ICD.Common.EventArguments
{
public sealed class DateTimeEventArgs : GenericEventArgs<DateTime>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public DateTimeEventArgs(DateTime data)
: base(data)
{
}
}
}

View File

@@ -0,0 +1,14 @@
namespace ICD.Common.EventArguments
{
public sealed class FloatEventArgs : GenericEventArgs<float>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public FloatEventArgs(float data)
: base(data)
{
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
namespace ICD.Common.EventArguments
{
public abstract class GenericEventArgs<T> : EventArgs
{
public T Data { get; private set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
protected GenericEventArgs(T data)
{
Data = data;
}
}
}

View File

@@ -0,0 +1,13 @@
namespace ICD.Common.EventArguments
{
public sealed class IntEventArgs : GenericEventArgs<int>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public IntEventArgs(int data) : base(data)
{
}
}
}

View File

@@ -0,0 +1,13 @@
namespace ICD.Common.EventArguments
{
public sealed class StringEventArgs : GenericEventArgs<string>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public StringEventArgs(string data) : base(data)
{
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using ICD.Common.Utils;
namespace ICD.Common.EventArguments
{
public sealed class TcpReceiveEventArgs : EventArgs
{
private readonly uint m_ClientId;
private readonly string m_Data;
public uint ClientId { get { return m_ClientId; } }
public string Data { get { return m_Data; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="clientId"></param>
/// <param name="data"></param>
public TcpReceiveEventArgs(uint clientId, IEnumerable<byte> data)
{
m_ClientId = clientId;
m_Data = StringUtils.ToString(data);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="clientId"></param>
/// <param name="data"></param>
/// <param name="length"></param>
public TcpReceiveEventArgs(uint clientId, IEnumerable<byte> data, int length)
{
m_ClientId = clientId;
m_Data = StringUtils.ToString(data, length);
}
}
}

View File

@@ -0,0 +1,16 @@
using ICD.Common.Properties;
namespace ICD.Common.EventArguments
{
[PublicAPI]
public sealed class UShortEventArgs : GenericEventArgs<ushort>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public UShortEventArgs(ushort data) : base(data)
{
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.EventArguments
{
public sealed class XmlRecursionEventArgs : EventArgs
{
[PublicAPI]
public string Outer { get; private set; }
[PublicAPI]
public string[] Path { get; private set; }
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
/// <param name="outer"></param>
/// <param name="path"></param>
public XmlRecursionEventArgs(string outer, string[] path)
{
Outer = outer;
Path = path;
}
#endregion
}
}

View File

@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netstandard1.6</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;STANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Remove="SIMPLSharpLogs\**" />
<EmbeddedResource Remove="SIMPLSharpLogs\**" />
<None Remove="SIMPLSharpLogs\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="ObfuscationSettings.cs" />
<Compile Remove="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="ICD.Common_SimplSharp.suo" />
<None Remove="ICD.SimplSharp.projectinfo" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,167 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{CB4055C6-D59E-479E-9C56-2C92335A7D9A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ICD.Common</RootNamespace>
<AssemblyName>ICD.Common</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;SIMPLSHARP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<GenerateSerializationAssemblies>off</GenerateSerializationAssemblies>
<DefineConstants>SIMPLSHARP</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\AbstractIcdAttribute.cs" />
<Compile Include="Attributes\KrangPluginAttribute.cs" />
<Compile Include="Attributes\Properties\SettingsProperty.cs" />
<Compile Include="Attributes\Rpc\RpcAttribute.cs" />
<Compile Include="EventArguments\BoolEventArgs.cs" />
<Compile Include="EventArguments\CharEventArgs.cs" />
<Compile Include="EventArguments\DateTimeEventArgs.cs" />
<Compile Include="EventArguments\FloatEventArgs.cs" />
<Compile Include="EventArguments\GenericEventArgs.cs" />
<Compile Include="EventArguments\IntEventArgs.cs" />
<Compile Include="EventArguments\StringEventArgs.cs" />
<Compile Include="EventArguments\TcpReceiveEventArgs.cs" />
<Compile Include="EventArguments\UShortEventArgs.cs" />
<Compile Include="EventArguments\XmlRecursionEventArgs.cs" />
<None Include="ObfuscationSettings.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\Logging\ILoggerService.cs" />
<Compile Include="Services\Logging\LogItem.cs" />
<Compile Include="Services\Logging\LogItemEventArgs.cs" />
<Compile Include="Services\Logging\SeverityEventArgs.cs" />
<Compile Include="Utils\AttributeUtils.cs" />
<Compile Include="Services\ServiceNotFoundException.cs" />
<Compile Include="Services\ServiceProvider.cs" />
<Compile Include="Utils\Collections\IcdHashSet.cs" />
<Compile Include="Utils\Collections\ScrollQueue.cs" />
<Compile Include="Utils\CrestronUtils.cs" />
<Compile Include="Utils\Extensions\DateTimeExtensions.cs" />
<Compile Include="Utils\Extensions\TypeExtensions.cs" />
<Compile Include="Utils\IcdConsole.cs" />
<Compile Include="Utils\IcdEnvironment.cs" />
<Compile Include="Utils\IcdEnvironment.SimplSharp.cs" />
<Compile Include="Utils\IcdEnvironment.Standard.cs" />
<Compile Include="Utils\IcdZip.cs" />
<Compile Include="Utils\IO\IcdDirectory.cs" />
<Compile Include="Utils\EnumUtils.cs" />
<Compile Include="Utils\Extensions\CollectionExtensions.cs" />
<Compile Include="Utils\Extensions\DictionaryExtensions.cs" />
<Compile Include="Utils\Extensions\EnumerableExtensions.cs" />
<Compile Include="Utils\Extensions\EnumExtensions.cs" />
<Compile Include="Utils\Extensions\EventHandlerExtensions.cs" />
<Compile Include="Utils\Extensions\JsonExtensions.cs" />
<Compile Include="Utils\Extensions\QueueExtensions.cs" />
<Compile Include="Utils\Extensions\ReflectionExtensions.cs" />
<Compile Include="Utils\Extensions\StringBuilderExtensions.cs" />
<Compile Include="Utils\Extensions\StringExtensions.cs" />
<Compile Include="Utils\Extensions\TimeSpanExtensions.cs" />
<Compile Include="Utils\IcdErrorLog.cs" />
<Compile Include="Utils\IO\IcdEncodingStringWriter.cs" />
<Compile Include="Utils\IO\IcdFile.cs" />
<Compile Include="Utils\IO\IcdFileStream.cs" />
<Compile Include="Utils\IO\IcdMemoryStream.cs" />
<Compile Include="Utils\IO\IcdPath.cs" />
<Compile Include="Utils\IO\IcdStream.cs" />
<Compile Include="Utils\IO\IcdStreamReader.cs" />
<Compile Include="Utils\IO\IcdStringReader.cs" />
<Compile Include="Utils\IO\IcdStringWriter.cs" />
<Compile Include="Utils\IO\IcdTextReader.cs" />
<Compile Include="Utils\IO\IcdTextWriter.cs" />
<Compile Include="Utils\IStateDisposable.cs" />
<Compile Include="Utils\Json\AbstractGenericJsonConverter.cs" />
<Compile Include="Utils\Json\JsonItemWrapper.cs" />
<Compile Include="Utils\Json\JsonUtils.cs" />
<Compile Include="Utils\MathUtils.cs" />
<Compile Include="Utils\PathUtils.cs" />
<Compile Include="Utils\PrettyPrint.cs" />
<Compile Include="Utils\ProgramUtils.cs" />
<Compile Include="Utils\ReflectionUtils.cs" />
<Compile Include="Utils\SafeCriticalSection.cs" />
<Compile Include="Utils\SafeCriticalSection.SimplSharp.cs" />
<Compile Include="Utils\SafeCriticalSection.Standard.cs" />
<Compile Include="Utils\SafeMutex.cs" />
<Compile Include="Utils\StringUtils.cs" />
<Compile Include="Utils\TableBuilder.cs" />
<Compile Include="Utils\Timers\IcdStopwatch.cs" />
<Compile Include="Utils\Timers\IcdTimer.cs" />
<Compile Include="Utils\Timers\Repeater.cs" />
<Compile Include="Utils\Timers\SafeTimer.cs" />
<Compile Include="Utils\TryUtils.cs" />
<Compile Include="Utils\Xml\IcdXmlConvert.cs" />
<Compile Include="Utils\Xml\IcdXmlDocument.cs" />
<Compile Include="Utils\Xml\IcdXmlException.cs" />
<Compile Include="Utils\Xml\IcdXmlReader.cs" />
<Compile Include="Utils\Xml\IcdXmlTextWriter.cs" />
<Compile Include="Utils\Xml\IcdXmlTextWriter.SimplSharp.cs" />
<Compile Include="Utils\Xml\IcdXmlAttribute.cs" />
<Compile Include="Utils\Xml\XmlReaderExtensions.cs" />
<Compile Include="Utils\Xml\XmlUtils.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>if /I "$(ConfigurationName)" == "Release" Eazfuscator.NET.exe "$(TargetPath)" --msbuild-project-path "$(ProjectPath)" --msbuild-project-configuration "$(ConfigurationName)" --msbuild-project-platform "$(PlatformName)" --msbuild-solution-path "$(SolutionPath)" -n --newline-flush -v 5.2 --configuration-file="$(ProjectDir)ObfuscationSettings.cs"
rem S# Pro preparation will execute after these operations</PostBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,6 @@
using System.Reflection;
[assembly: Obfuscation(Feature = "platform api: System.Threading.Thread, System.Reflection.*, System.IO.Stream, System.Windows.Forms.*", Exclude = true)]
[assembly: Obfuscation(Feature = "rename symbol names with printable characters", Exclude = false)]
[assembly: Obfuscation(Feature = "code control flow obfuscation", Exclude = false)]
[assembly: Obfuscation(Feature = "Apply to type * when class: renaming", Exclude = true, ApplyToMembers = false)]

View File

@@ -0,0 +1,713 @@
using System;
#pragma warning disable 1591
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedParameter.Local
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable IntroduceOptionalParameters.Global
// ReSharper disable MemberCanBeProtected.Global
// ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace
namespace ICD.Common.Properties
{
/// <summary>
/// Indicates that the value of the marked element could be <c>null</c> sometimes,
/// so the check for <c>null</c> is necessary before its usage
/// </summary>
/// <example><code>
/// [CanBeNull] public object Test() { return null; }
/// public void UseTest() {
/// var p = Test();
/// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException'
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.Delegate |
AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class CanBeNullAttribute : Attribute
{
}
/// <summary>
/// Indicates that the value of the marked element could never be <c>null</c>
/// </summary>
/// <example><code>
/// [NotNull] public object Foo() {
/// return null; // Warning: Possible 'null' assignment
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Parameter |
AttributeTargets.Property | AttributeTargets.Delegate |
AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public sealed class NotNullAttribute : Attribute
{
}
/// <summary>
/// Indicates that the marked method builds string by format pattern and (optional) arguments.
/// Parameter, which contains format string, should be given in constructor. The format string
/// should be in <see cref="string.Format(IFormatProvider,string,object[])"/>-like form
/// </summary>
/// <example><code>
/// [StringFormatMethod("message")]
/// public void ShowError(string message, params object[] args) { /* do something */ }
/// public void Foo() {
/// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Constructor | AttributeTargets.Method,
AllowMultiple = false, Inherited = true)]
public sealed class StringFormatMethodAttribute : Attribute
{
/// <param name="formatParameterName">
/// Specifies which parameter of an annotated method should be treated as format-string
/// </param>
public StringFormatMethodAttribute(string formatParameterName)
{
FormatParameterName = formatParameterName;
}
public string FormatParameterName { get; private set; }
}
/// <summary>
/// Indicates that the function argument should be string literal and match one
/// of the parameters of the caller function. For example, ReSharper annotates
/// the parameter of <see cref="System.ArgumentNullException"/>
/// </summary>
/// <example><code>
/// public void Foo(string param) {
/// if (param == null)
/// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public sealed class InvokerParameterNameAttribute : Attribute
{
}
/// <summary>
/// Indicates that the method is contained in a type that implements
/// <see cref="System.ComponentModel.INotifyPropertyChanged"/> interface
/// and this method is used to notify that some property value changed
/// </summary>
/// <remarks>
/// The method should be non-static and conform to one of the supported signatures:
/// <list>
/// <item><c>NotifyChanged(string)</c></item>
/// <item><c>NotifyChanged(params string[])</c></item>
/// <item><c>NotifyChanged{T}(Expression{Func{T}})</c></item>
/// <item><c>NotifyChanged{T,U}(Expression{Func{T,U}})</c></item>
/// <item><c>SetProperty{T}(ref T, T, string)</c></item>
/// </list>
/// </remarks>
/// <example><code>
/// public class Foo : INotifyPropertyChanged {
/// public event PropertyChangedEventHandler PropertyChanged;
/// [NotifyPropertyChangedInvocator]
/// protected virtual void NotifyChanged(string propertyName) { ... }
///
/// private string _name;
/// public string Name {
/// get { return _name; }
/// set { _name = value; NotifyChanged("LastName"); /* Warning */ }
/// }
/// }
/// </code>
/// Examples of generated notifications:
/// <list>
/// <item><c>NotifyChanged("Property")</c></item>
/// <item><c>NotifyChanged(() =&gt; Property)</c></item>
/// <item><c>NotifyChanged((VM x) =&gt; x.Property)</c></item>
/// <item><c>SetProperty(ref myField, value, "Property")</c></item>
/// </list>
/// </example>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute()
{
}
public NotifyPropertyChangedInvocatorAttribute(string parameterName)
{
ParameterName = parameterName;
}
public string ParameterName { get; private set; }
}
/// <summary>
/// Describes dependency between method input and output
/// </summary>
/// <syntax>
/// <p>Function Definition Table syntax:</p>
/// <list>
/// <item>FDT ::= FDTRow [;FDTRow]*</item>
/// <item>FDTRow ::= Input =&gt; Output | Output &lt;= Input</item>
/// <item>Input ::= ParameterName: Value [, Input]*</item>
/// <item>Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value}</item>
/// <item>Value ::= true | false | null | notnull | canbenull</item>
/// </list>
/// If method has single input parameter, it's name could be omitted.<br/>
/// Using <c>halt</c> (or <c>void</c>/<c>nothing</c>, which is the same)
/// for method output means that the methos doesn't return normally.<br/>
/// <c>canbenull</c> annotation is only applicable for output parameters.<br/>
/// You can use multiple <c>[ContractAnnotation]</c> for each FDT row,
/// or use single attribute with rows separated by semicolon.<br/>
/// </syntax>
/// <examples><list>
/// <item><code>
/// [ContractAnnotation("=> halt")]
/// public void TerminationMethod()
/// </code></item>
/// <item><code>
/// [ContractAnnotation("halt &lt;= condition: false")]
/// public void Assert(bool condition, string text) // regular assertion method
/// </code></item>
/// <item><code>
/// [ContractAnnotation("s:null => true")]
/// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty()
/// </code></item>
/// <item><code>
/// // A method that returns null if the parameter is null, and not null if the parameter is not null
/// [ContractAnnotation("null => null; notnull => notnull")]
/// public object Transform(object data)
/// </code></item>
/// <item><code>
/// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")]
/// public bool TryParse(string s, out Person result)
/// </code></item>
/// </list></examples>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class ContractAnnotationAttribute : Attribute
{
public ContractAnnotationAttribute([NotNull] string contract)
: this(contract, false)
{
}
public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)
{
Contract = contract;
ForceFullStates = forceFullStates;
}
public string Contract { get; private set; }
public bool ForceFullStates { get; private set; }
}
/// <summary>
/// Indicates that marked element should be localized or not
/// </summary>
/// <example><code>
/// [LocalizationRequiredAttribute(true)]
/// public class Foo {
/// private string str = "my string"; // Warning: Localizable string
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class LocalizationRequiredAttribute : Attribute
{
public LocalizationRequiredAttribute() : this(true)
{
}
public LocalizationRequiredAttribute(bool required)
{
Required = required;
}
public bool Required { get; private set; }
}
/// <summary>
/// Indicates that the value of the marked type (or its derivatives)
/// cannot be compared using '==' or '!=' operators and <c>Equals()</c>
/// should be used instead. However, using '==' or '!=' for comparison
/// with <c>null</c> is always permitted.
/// </summary>
/// <example><code>
/// [CannotApplyEqualityOperator]
/// class NoEquality { }
/// class UsesNoEquality {
/// public void Test() {
/// var ca1 = new NoEquality();
/// var ca2 = new NoEquality();
/// if (ca1 != null) { // OK
/// bool condition = ca1 == ca2; // Warning
/// }
/// }
/// }
/// </code></example>
[AttributeUsage(
AttributeTargets.Interface | AttributeTargets.Class |
AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
public sealed class CannotApplyEqualityOperatorAttribute : Attribute
{
}
/// <summary>
/// When applied to a target attribute, specifies a requirement for any type marked
/// with the target attribute to implement or inherit specific type or types.
/// </summary>
/// <example><code>
/// [BaseTypeRequired(typeof(IComponent)] // Specify requirement
/// public class ComponentAttribute : Attribute { }
/// [Component] // ComponentAttribute requires implementing IComponent interface
/// public class MyComponent : IComponent { }
/// </code></example>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
[BaseTypeRequired(typeof(Attribute))]
public sealed class BaseTypeRequiredAttribute : Attribute
{
public BaseTypeRequiredAttribute([NotNull] Type baseType)
{
BaseType = baseType;
}
[NotNull]
public Type BaseType { get; private set; }
}
/// <summary>
/// Indicates that the marked symbol is used implicitly
/// (e.g. via reflection, in external library), so this symbol
/// will not be marked as unused (as well as by other usage inspections)
/// </summary>
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public sealed class UsedImplicitlyAttribute : Attribute
{
public UsedImplicitlyAttribute()
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Itself)
{
}
public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
: this(useKindFlags, ImplicitUseTargetFlags.Itself)
{
}
public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
: this(ImplicitUseKindFlags.Default, targetFlags)
{
}
public UsedImplicitlyAttribute(
ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
{
UseKindFlags = useKindFlags;
TargetFlags = targetFlags;
}
public ImplicitUseKindFlags UseKindFlags { get; private set; }
public ImplicitUseTargetFlags TargetFlags { get; private set; }
}
/// <summary>
/// Should be used on attributes and causes ReSharper
/// to not mark symbols marked with such attributes as unused
/// (as well as by other usage inspections)
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class MeansImplicitUseAttribute : Attribute
{
public MeansImplicitUseAttribute()
: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Itself)
{
}
public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
: this(useKindFlags, ImplicitUseTargetFlags.Itself)
{
}
public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
: this(ImplicitUseKindFlags.Default, targetFlags)
{
}
public MeansImplicitUseAttribute(
ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
{
UseKindFlags = useKindFlags;
TargetFlags = targetFlags;
}
[UsedImplicitly]
public ImplicitUseKindFlags UseKindFlags { get; private set; }
[UsedImplicitly]
public ImplicitUseTargetFlags TargetFlags { get; private set; }
}
[Flags]
public enum ImplicitUseKindFlags
{
Default = Access | Assign | InstantiatedWithFixedConstructorSignature,
/// <summary>Only entity marked with attribute considered used</summary>
Access = 1,
/// <summary>Indicates implicit assignment to a member</summary>
Assign = 2,
/// <summary>
/// Indicates implicit instantiation of a type with fixed constructor signature.
/// That means any unused constructor parameters won't be reported as such.
/// </summary>
InstantiatedWithFixedConstructorSignature = 4,
/// <summary>Indicates implicit instantiation of a type</summary>
InstantiatedNoFixedConstructorSignature = 8,
}
/// <summary>
/// Specify what is considered used implicitly
/// when marked with <see cref="MeansImplicitUseAttribute"/>
/// or <see cref="UsedImplicitlyAttribute"/>
/// </summary>
[Flags]
public enum ImplicitUseTargetFlags
{
Itself = 1,
/// <summary>Members of entity marked with attribute are considered used</summary>
Members = 2,
/// <summary>Entity marked with attribute and all its members considered used</summary>
WithMembers = Itself | Members
}
/// <summary>
/// This attribute is intended to mark publicly available API
/// which should not be removed and so is treated as used
/// </summary>
[MeansImplicitUse]
public sealed class PublicAPIAttribute : Attribute
{
public PublicAPIAttribute()
{
}
public PublicAPIAttribute([NotNull] string comment)
{
Comment = comment;
}
[NotNull]
public string Comment { get; private set; }
}
/// <summary>
/// Tells code analysis engine if the parameter is completely handled
/// when the invoked method is on stack. If the parameter is a delegate,
/// indicates that delegate is executed while the method is executed.
/// If the parameter is an enumerable, indicates that it is enumerated
/// while the method is executed
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = true)]
public sealed class InstantHandleAttribute : Attribute
{
}
/// <summary>
/// Indicates that a method does not make any observable state changes.
/// The same as <c>System.Diagnostics.Contracts.PureAttribute</c>
/// </summary>
/// <example><code>
/// [Pure] private int Multiply(int x, int y) { return x * y; }
/// public void Foo() {
/// const int a = 2, b = 2;
/// Multiply(a, b); // Waring: Return value of pure method is not used
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public sealed class PureAttribute : Attribute
{
}
/// <summary>
/// Indicates that a parameter is a path to a file or a folder
/// within a web project. Path can be relative or absolute,
/// starting from web root (~)
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class PathReferenceAttribute : Attribute
{
public PathReferenceAttribute()
{
}
public PathReferenceAttribute([PathReference] string basePath)
{
BasePath = basePath;
}
[NotNull]
public string BasePath { get; private set; }
}
// ASP.NET MVC attributes
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute
{
public AspMvcAreaMasterLocationFormatAttribute(string format)
{
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute
{
public AspMvcAreaPartialViewLocationFormatAttribute(string format)
{
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute
{
public AspMvcAreaViewLocationFormatAttribute(string format)
{
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcMasterLocationFormatAttribute : Attribute
{
public AspMvcMasterLocationFormatAttribute(string format)
{
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute
{
public AspMvcPartialViewLocationFormatAttribute(string format)
{
}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class AspMvcViewLocationFormatAttribute : Attribute
{
public AspMvcViewLocationFormatAttribute(string format)
{
}
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC action. If applied to a method, the MVC action name is calculated
/// implicitly from the context. Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcActionAttribute : Attribute
{
public AspMvcActionAttribute()
{
}
public AspMvcActionAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull]
public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC area.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcAreaAttribute : PathReferenceAttribute
{
public AspMvcAreaAttribute()
{
}
public AspMvcAreaAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull]
public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that
/// the parameter is an MVC controller. If applied to a method,
/// the MVC controller name is calculated implicitly from the context.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcControllerAttribute : Attribute
{
public AspMvcControllerAttribute()
{
}
public AspMvcControllerAttribute([NotNull] string anonymousProperty)
{
AnonymousProperty = anonymousProperty;
}
[NotNull]
public string AnonymousProperty { get; private set; }
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(String, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcMasterAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(String, Object)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcModelTypeAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that
/// the parameter is an MVC partial view. If applied to a method,
/// the MVC partial view name is calculated implicitly from the context.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute
{
}
/// <summary>
/// ASP.NET MVC attribute. Allows disabling all inspections
/// for MVC views within a class or a method.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class AspMvcSupressViewErrorAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcDisplayTemplateAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcEditorTemplateAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. Indicates that a parameter is an MVC template.
/// Use this attribute for custom wrappers similar to
/// <c>System.ComponentModel.DataAnnotations.UIHintAttribute(System.String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class AspMvcTemplateAttribute : Attribute
{
}
/// <summary>
/// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter
/// is an MVC view. If applied to a method, the MVC view name is calculated implicitly
/// from the context. Use this attribute for custom wrappers similar to
/// <c>System.Web.Mvc.Controller.View(Object)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)]
public sealed class AspMvcViewAttribute : PathReferenceAttribute
{
}
/// <summary>
/// ASP.NET MVC attribute. When applied to a parameter of an attribute,
/// indicates that this parameter is an MVC action name
/// </summary>
/// <example><code>
/// [ActionName("Foo")]
/// public ActionResult Login(string returnUrl) {
/// ViewBag.ReturnUrl = Url.Action("Foo"); // OK
/// return RedirectToAction("Bar"); // Error: Cannot resolve action
/// }
/// </code></example>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class AspMvcActionSelectorAttribute : Attribute
{
}
[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Property |
AttributeTargets.Field, Inherited = true)]
public sealed class HtmlElementAttributesAttribute : Attribute
{
public HtmlElementAttributesAttribute()
{
}
public HtmlElementAttributesAttribute([NotNull] string name)
{
Name = name;
}
[NotNull]
public string Name { get; private set; }
}
[AttributeUsage(
AttributeTargets.Parameter | AttributeTargets.Field |
AttributeTargets.Property, Inherited = true)]
public sealed class HtmlAttributeValueAttribute : Attribute
{
public HtmlAttributeValueAttribute([NotNull] string name)
{
Name = name;
}
[NotNull]
public string Name { get; private set; }
}
// Razor attributes
/// <summary>
/// Razor attribute. Indicates that a parameter or a method is a Razor section.
/// Use this attribute for custom wrappers similar to
/// <c>System.Web.WebPages.WebPageBase.RenderSection(String)</c>
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)]
public sealed class RazorSectionAttribute : Attribute
{
}
}

View File

@@ -0,0 +1,7 @@
using System.Reflection;
[assembly: AssemblyTitle("ICD.SimplSharp.Common")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ICD.SimplSharp.Common")]
[assembly: AssemblyCopyright("Copyright © ICD Systems 2017")]
[assembly: AssemblyVersion("1.0.1.*")]

View File

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils;
namespace ICD.Common.Services.Logging
{
public enum eSeverity
{
Emergency = 0,
Alert = 1,
Critical = 2,
Error = 3,
Warning = 4,
Notice = 5,
Informational = 6,
Debug = 7
}
public interface ILoggerService
{
[PublicAPI]
event EventHandler<LogItemEventArgs> OnEntryAdded;
[PublicAPI]
event EventHandler<SeverityEventArgs> OnSeverityLevelChanged;
/// <summary>
/// Gets and sets the severity level.
/// </summary>
[PublicAPI]
eSeverity SeverityLevel { get; set; }
/// <summary>
/// Adds the log item.
/// </summary>
/// <param name="item">Log entry to add</param>
[PublicAPI]
void AddEntry(LogItem item);
/// <summary>
/// Gets the log history.
/// </summary>
/// <returns></returns>
[PublicAPI]
KeyValuePair<int, LogItem>[] GetHistory();
}
/// <summary>
/// Extension methods for ILoggerService.
/// </summary>
public static class LoggerServiceExtensions
{
/// <summary>
/// Adds the log item with string formatting.
/// </summary>
/// <param name="extends"></param>
/// <param name="severity">Severity Code, 0 - 7</param>
/// <param name="message">Message Text format string</param>
[PublicAPI]
public static void AddEntry(this ILoggerService extends, eSeverity severity, string message)
{
LogItem item = new LogItem(severity, message);
extends.AddEntry(item);
}
/// <summary>
/// Adds the log item with string formatting.
/// </summary>
/// <param name="extends"></param>
/// <param name="severity">Severity Code, 0 - 7</param>
/// <param name="message">Message Text format string</param>
/// <param name="args">objects to format into the string</param>
[PublicAPI]
public static void AddEntry(this ILoggerService extends, eSeverity severity, string message, params object[] args)
{
extends.AddEntry(severity, string.Format(message, args));
}
[PublicAPI]
public static void AddEntry(this ILoggerService extends, eSeverity severity, Exception e, string message)
{
extends.AddEntry(severity, string.Format("{0}: {1}{2}{3}{2}{4}", e.GetType().Name, message,
IcdEnvironment.NewLine, e.Message, e.StackTrace));
}
[PublicAPI]
public static void AddEntry(this ILoggerService extends, eSeverity severity, Exception e, string message,
params object[] args)
{
extends.AddEntry(severity, e, string.Format(message, args));
}
}
}

View File

@@ -0,0 +1,126 @@
using System;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils;
namespace ICD.Common.Services.Logging
{
/// <summary>
/// Log Entry Item
/// </summary>
public struct LogItem
{
private readonly string m_Message;
private readonly eSeverity m_Severity;
private readonly DateTime m_Timestamp;
#region Properties
/// <summary>
/// Accessor only for timestamp.
/// </summary>
[PublicAPI]
public DateTime Timestamp { get { return m_Timestamp; } }
/// <summary>
/// Get/Set for severity level.
/// </summary>
public eSeverity Severity { get { return m_Severity; } }
/// <summary>
/// Get/Set for message string.
/// </summary>
public string Message { get { return m_Message; } }
#endregion
#region Constructors
/// <summary>
/// Creates a new LogItem object with the specified values.
/// </summary>
/// <param name="severity">Severity Level, between 0 and 7</param>
/// <param name="message">Error message text</param>
public LogItem(eSeverity severity, string message)
{
m_Severity = severity;
m_Message = message;
m_Timestamp = IcdEnvironment.GetLocalTime();
}
#endregion
#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>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator ==(LogItem a1, LogItem a2)
{
return a1.Equals(a2);
}
/// <summary>
/// Implementing default inequality.
/// </summary>
/// <param name="a1"></param>
/// <param name="a2"></param>
/// <returns></returns>
public static bool operator !=(LogItem a1, LogItem a2)
{
return !(a1 == a2);
}
/// <summary>
/// Returns true if this instance is equal to the given object.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public override bool Equals(object other)
{
if (other == null || GetType() != other.GetType())
return false;
return GetHashCode() == ((LogItem)other).GetHashCode();
}
/// <summary>
/// Gets the hashcode for this instance.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (m_Message == null ? 0 : m_Message.GetHashCode());
hash = hash * 23 + (int)m_Timestamp.Ticks;
hash = hash * 23 + (int)m_Severity;
return hash;
}
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
using ICD.Common.EventArguments;
namespace ICD.Common.Services.Logging
{
public sealed class LogItemEventArgs : GenericEventArgs<LogItem>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="item"></param>
public LogItemEventArgs(LogItem item)
: base(item)
{
}
}
}

View File

@@ -0,0 +1,16 @@
using ICD.Common.EventArguments;
namespace ICD.Common.Services.Logging
{
public sealed class SeverityEventArgs : GenericEventArgs<eSeverity>
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="data"></param>
public SeverityEventArgs(eSeverity data)
: base(data)
{
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace ICD.Common.Services
{
public sealed class ServiceNotFoundException : Exception
{
private const string DEFAULT_MESSAGE = "The requested service {0} was not found in the service provider";
public Type ServiceType { get; set; }
public ServiceNotFoundException()
{
}
public ServiceNotFoundException(string message) : base(message)
{
}
public ServiceNotFoundException(string message, Exception inner) : base(message, inner)
{
}
public ServiceNotFoundException(Type type) : base(string.Format(DEFAULT_MESSAGE, type.Name))
{
ServiceType = type;
}
}
}

View File

@@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils;
namespace ICD.Common.Services
{
public sealed class ServiceProvider : IDisposable
{
#region Static
private static ServiceProvider s_Instance;
private static ServiceProvider Instance { get { return s_Instance ?? (s_Instance = new ServiceProvider()); } }
/// <summary>
/// Retrieves the registered service of the given type. Use this for required dependencies.
/// </summary>
/// <typeparam name="TService">service type to retrieve</typeparam>
/// <returns></returns>
/// <exception cref="ServiceNotFoundException">Thrown if a service of the given type is not registered</exception>
[PublicAPI]
[NotNull]
public static TService GetService<TService>()
{
return (TService)GetService(typeof(TService));
}
/// <summary>
/// Retrieves the registered service of the given type. Use this for required dependencies.
/// </summary>
/// <param name="tService">service type to retrieve</param>
/// <returns></returns>
/// <exception cref="ServiceNotFoundException">Thrown if a service of the given type is not registered</exception>
[PublicAPI]
[NotNull]
public static object GetService(Type tService)
{
return Instance.GetServiceInstance(tService);
}
/// <summary>
/// Retrieves the registered service of the given type. Returns null if the service type was not found.
/// Use this for optional dependencies.
/// </summary>
/// <typeparam name="TService">service type to retrieve</typeparam>
/// <returns>requested service or null if that service type is not registered</returns>
[PublicAPI]
[CanBeNull]
public static TService TryGetService<TService>()
{
return (TService)TryGetService(typeof(TService));
}
/// <summary>
/// Retrieves the registered service of the given type. Returns null if the service type was not found.
/// Use this for optional dependencies.
/// </summary>
/// <param name="tService">service type to retrieve</param>
/// <returns>requested service or null if that service type is not registered</returns>
[PublicAPI]
[CanBeNull]
public static object TryGetService(Type tService)
{
try
{
return Instance.GetServiceInstance(tService);
}
catch (ServiceNotFoundException)
{
return null;
}
}
/// <summary>
/// Registers a service instance to the type given.
/// </summary>
/// <typeparam name="TService"></typeparam>
/// <param name="service"></param>
[PublicAPI]
public static void AddService<TService>(TService service)
{
AddService(typeof(TService), service);
}
/// <summary>
/// Registers a service instance to the type given.
/// </summary>
/// <param name="tService"></param>
/// <param name="service"></param>
[PublicAPI]
public static void AddService(Type tService, object service)
{
Instance.AddServiceInstance(tService, service);
}
#endregion
private readonly Dictionary<Type, object> m_Services = new Dictionary<Type, object>();
private readonly SafeCriticalSection m_ServicesSection = new SafeCriticalSection();
#region Methods
private object GetServiceInstance(Type tService)
{
try
{
m_ServicesSection.Enter();
object service;
if (m_Services.TryGetValue(tService, out service) && service != null)
return service;
throw new ServiceNotFoundException(tService);
}
finally
{
m_ServicesSection.Leave();
}
}
[PublicAPI]
private void AddServiceInstance(Type tService, object service)
{
m_ServicesSection.Enter();
m_Services[tService] = service;
m_ServicesSection.Leave();
}
#endregion
#region IDisposable
public void Dispose()
{
try
{
m_ServicesSection.Enter();
foreach (object service in m_Services.Values.Distinct())
{
if (!(service is IDisposable))
continue;
((IDisposable)service).Dispose();
}
m_Services.Clear();
}
finally
{
m_ServicesSection.Leave();
}
}
public static void DisposeStatic()
{
if (s_Instance != null)
s_Instance.Dispose();
s_Instance = null;
}
#endregion
}
}

View File

@@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// Utility methods for browsing code attributes.
/// Provides some basic caching for faster subsequent searches.
/// </summary>
public static class AttributeUtils
{
// Avoid caching the same assembly multiple times.
private static readonly IcdHashSet<Assembly> s_CachedAssemblies;
private static readonly IcdHashSet<Type> s_CachedTypes;
private static readonly Dictionary<Attribute, MethodInfo> s_AttributeToMethodCache;
private static readonly Dictionary<Type, IcdHashSet<Attribute>> s_TypeToAttributesCache;
/// <summary>
/// Constructor.
/// </summary>
static AttributeUtils()
{
s_CachedAssemblies = new IcdHashSet<Assembly>();
s_CachedTypes = new IcdHashSet<Type>();
s_AttributeToMethodCache = new Dictionary<Attribute, MethodInfo>();
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
}
#region Caching
/// <summary>
/// Pre-emptively caches the given assemblies for lookup.
/// </summary>
/// <param name="assemblies"></param>
public static void CacheAssemblies(IEnumerable<Assembly> assemblies)
{
if (assemblies == null)
throw new ArgumentNullException("assemblies");
foreach (Assembly assembly in assemblies)
CacheAssembly(assembly);
}
/// <summary>
/// Pre-emptively caches the given assembly for lookup.
/// </summary>
/// <param name="assembly"></param>
public static void CacheAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
if (s_CachedAssemblies.Contains(assembly))
return;
s_CachedAssemblies.Add(assembly);
#if SIMPLSHARP
CType[] types = new CType[0];
#else
Type[] types = new Type[0];
#endif
try
{
types = assembly.GetTypes();
}
catch (TypeLoadException e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, "Failed to cache assembly {0} - {1}", assembly.GetName().Name,
e.Message);
}
foreach (var type in types)
CacheType(type);
}
/// <summary>
/// Pre-emptively caches the given type for lookup.
/// </summary>
/// <param name="type"></param>
#if SIMPLSHARP
public static void CacheType(CType type)
#else
public static void CacheType(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
if (s_CachedTypes.Contains(type))
return;
s_CachedTypes.Add(type);
MethodInfo[] methods;
try
{
#if SIMPLSHARP
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
methods = type.GetMethods();
#else
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetTypeInfo().GetCustomAttributes<Attribute>(false));
methods = type.GetTypeInfo().GetMethods();
#endif
}
// GetMethods for Open Generic Types is not supported.
catch (NotSupportedException)
{
return;
}
// Not sure why this happens :/
catch (InvalidProgramException)
{
return;
}
foreach (MethodInfo method in methods)
CacheMethod(method);
}
/// <summary>
/// Caches the method.
/// </summary>
/// <param name="method"></param>
private static void CacheMethod(MethodInfo method)
{
if (method == null)
throw new ArgumentNullException("method");
foreach (Attribute attribute in method.GetCustomAttributes<Attribute>(false))
s_AttributeToMethodCache[attribute] = method;
}
#endregion
#region Lookup
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes<T>(type).FirstOrDefault();
}
/// <summary>
/// Gets the attributes on the given class type matching the generic type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<T> GetClassAttributes<T>(Type type)
where T : Attribute
{
if (type == null)
throw new ArgumentNullException("type");
return GetClassAttributes(type).OfType<T>();
}
/// <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);
return s_TypeToAttributesCache.ContainsKey(type)
? s_TypeToAttributesCache[type].ToArray()
: Enumerable.Empty<Attribute>();
}
/// <summary>
/// Gets all of the cached method attributes of the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetMethodAttributes<T>()
where T : Attribute
{
return s_AttributeToMethodCache.Select(p => p.Key)
.OfType<T>()
.ToArray();
}
/// <summary>
/// Gets the cached method for the given attribute.
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static MethodInfo GetMethod(Attribute attribute)
{
if (attribute == null)
throw new ArgumentNullException("attribute");
return s_AttributeToMethodCache[attribute];
}
#endregion
}
}

View File

@@ -0,0 +1,269 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// A collection containing only unique items.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class IcdHashSet<T> : ICollection<T>
{
private readonly Dictionary<T, object> m_Dict;
#region Properties
/// <summary>
/// Returns a new, empty hashset.
/// </summary>
[PublicAPI]
public static IcdHashSet<T> NullSet { get { return new IcdHashSet<T>(); } }
/// <summary>
/// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// The number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
public int Count { get { return m_Dict.Count; } }
/// <summary>
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </summary>
/// <returns>
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
/// </returns>
public bool IsReadOnly { get { return false; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdHashSet()
{
m_Dict = new Dictionary<T, object>();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="items"></param>
public IcdHashSet(IEnumerable<T> items)
: this()
{
if (items == null)
return;
AddRange(items);
}
#endregion
#region Methods
[PublicAPI]
public IcdHashSet<T> Union(IEnumerable<T> set)
{
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
if (set == null)
return unionSet;
unionSet.AddRange(set);
return unionSet;
}
[PublicAPI]
public IcdHashSet<T> Subtract(IEnumerable<T> set)
{
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
if (set == null)
return subtractSet;
foreach (T item in set)
subtractSet.Remove(item);
return subtractSet;
}
[PublicAPI]
public bool IsSubsetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return this.All(setToCompare.Contains);
}
[PublicAPI]
public IcdHashSet<T> Intersection(IcdHashSet<T> set)
{
IcdHashSet<T> intersectionSet = NullSet;
if (set == null)
return intersectionSet;
foreach (T item in this.Where(set.Contains))
intersectionSet.Add(item);
foreach (T item in set.Where(Contains))
intersectionSet.Add(item);
return intersectionSet;
}
/// <summary>
/// Returns items that are not common between both sets.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> NonIntersection(IcdHashSet<T> set)
{
return Subtract(set).Union(set.Subtract(this));
}
[PublicAPI]
public bool IsProperSubsetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
// Is a proper subset if A is a subset of B and A != B
return (IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this));
}
[PublicAPI]
public bool IsSupersetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
return setToCompare.IsSubsetOf(this);
}
[PublicAPI]
public bool IsProperSupersetOf(IcdHashSet<T> set)
{
IcdHashSet<T> setToCompare = set ?? NullSet;
// B is a proper superset of A if B is a superset of A and A != B
return (IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this));
}
#endregion
#region ICollection<T> Members
/// <summary>
/// Adds the item to the collection. Returns false if the item already exists.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Add(T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("item");
if (m_Dict.ContainsKey(item))
return false;
m_Dict[item] = null;
return true;
}
/// <summary>
/// Adds the item to the collection.
/// </summary>
/// <param name="item"></param>
void ICollection<T>.Add(T item)
{
Add(item);
}
/// <summary>
/// Adds each of the items in the sequence to the collection.
/// </summary>
/// <param name="items"></param>
public void AddRange(IEnumerable<T> items)
{
foreach (T item in items)
Add(item);
}
/// <summary>
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
public void Clear()
{
m_Dict.Clear();
}
/// <summary>
/// Returns true if the IcdHashSet contains the given item.
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
return m_Dict.ContainsKey(item);
}
/// <summary>
/// Copies the items of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the items copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of items in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type T cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
{
m_Dict.Keys.CopyTo(array, arrayIndex);
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </summary>
/// <returns>
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item)
{
return m_Dict.Remove(item);
}
#endregion
#region Implementation of IEnumerable
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<T> GetEnumerator()
{
return m_Dict.Keys.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}

View File

@@ -0,0 +1,180 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Collections
{
/// <summary>
/// ScrollQueue is a queue that never exceeds a predefined length. Old items
/// are removed as new items are added.
/// </summary>
/// <typeparam name="TContents"></typeparam>
public sealed class ScrollQueue<TContents> : IEnumerable<TContents>, ICollection
{
private readonly LinkedList<TContents> m_Collection;
private int m_MaxSize;
private readonly SafeCriticalSection m_CollectionLock;
#region Properties
/// <summary>
/// Gets/sets the maximum size of the queue.
/// </summary>
[PublicAPI]
public int MaxSize
{
get { return m_MaxSize; }
set
{
if (value == m_MaxSize)
return;
m_MaxSize = value;
Trim();
}
}
/// <summary>
/// Gets the number of items in the collection.
/// </summary>
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 true; } }
/// <summary>
/// The SyncRoot property returns an object, which is used for synchronizing
/// the collection. This returns the instance of the object or returns the
/// SyncRoot of other collections if the collection contains other collections.
/// </summary>
public object SyncRoot { get { return this; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
/// <param name="maxSize"></param>
public ScrollQueue(int maxSize)
{
m_CollectionLock = new SafeCriticalSection();
m_Collection = new LinkedList<TContents>();
MaxSize = maxSize;
}
#region Queue Methods
/// <summary>
/// Clears all items from the queue.
/// </summary>
public void Clear()
{
m_CollectionLock.Execute(() => m_Collection.Clear());
}
/// <summary>
/// Appends the item to the queue, trims old items that exceed max length.
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void Enqueue(TContents item)
{
m_CollectionLock.Execute(() => m_Collection.AddLast(item));
Trim();
}
/// <summary>
/// Removes the oldest item from the queue.
/// </summary>
/// <returns></returns>
[PublicAPI]
public TContents Dequeue()
{
m_CollectionLock.Enter();
try
{
TContents output = m_Collection.First.Value;
m_Collection.RemoveFirst();
return output;
}
finally
{
m_CollectionLock.Leave();
}
}
/// <summary>
/// Returns the oldest item in the queue.
/// </summary>
/// <returns></returns>
[PublicAPI]
public TContents Peek()
{
return m_CollectionLock.Execute(() => m_Collection.First.Value);
}
#endregion
#region Implemented Methods
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<TContents> GetEnumerator()
{
return m_CollectionLock.Execute(() => m_Collection.ToList().GetEnumerator());
}
void ICollection.CopyTo(Array myArr, int index)
{
m_CollectionLock.Enter();
try
{
foreach (TContents item in m_Collection)
{
myArr.SetValue(item, index);
index++;
}
}
finally
{
m_CollectionLock.Leave();
}
}
#endregion
#region Private Methods
/// <summary>
/// Removes items that fall outside of the max size.
/// </summary>
private void Trim()
{
m_CollectionLock.Enter();
try
{
while (Count > MaxSize)
m_Collection.RemoveFirst();
}
finally
{
m_CollectionLock.Leave();
}
}
#endregion
}
}

View File

@@ -0,0 +1,245 @@
#if SIMPLSHARP
using System;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
namespace ICD.Common.Utils
{
public static class CrestronUtils
{
private const string MODEL_NAME_REGEX = @"^(\S*)";
private const string MODEL_VERSION_REGEX = @" [[]v(\S*)";
private const string RAMFREE_COMMAND = "ramfree";
private const string RAMFREE_DIGITS_REGEX = @"^(\d*)";
private static string s_VersionResult;
#region Properties
/// <summary>
/// Gets the default mac address of the processor.
/// </summary>
[PublicAPI]
public static string DefaultMacAddress
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
return CrestronEthernetHelper.GetEthernetParameter(param, id);
}
}
/// <summary>
/// Gets the version text from the console.
/// </summary>
private static string VersionResult
{
get
{
if (string.IsNullOrEmpty(s_VersionResult))
{
if (!CrestronConsole.SendControlSystemCommand("version", ref s_VersionResult))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(CrestronUtils).Name, "version");
}
}
return s_VersionResult;
}
}
/// <summary>
/// Gets the model name of the processor.
/// </summary>
[PublicAPI]
public static string ModelName
{
get
{
Regex regex = new Regex(MODEL_NAME_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return match.Groups[1].Value;
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model name from \"{0}\"", VersionResult);
return string.Empty;
}
}
/// <summary>
/// Gets the processor firmware version.
/// </summary>
[PublicAPI]
public static Version ModelVersion
{
get
{
Regex regex = new Regex(MODEL_VERSION_REGEX);
Match match = regex.Match(VersionResult);
if (match.Success)
return new Version(match.Groups[1].Value);
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "Unable to get model version from \"{0}\"", VersionResult);
return new Version(0, 0);
}
}
/// <summary>
/// Gets the ram usage in the range 0 - 1.
/// </summary>
public static float RamUsagePercent
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[0].Groups[1].Value;
return float.Parse(digits) / 100.0f;
}
}
/// <summary>
/// Gets the total number of bytes of physical memory.
/// </summary>
public static ulong RamTotalBytes
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[1].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes of physical memory being used by the control system.
/// </summary>
public static ulong RamUsedBytes
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[2].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes of physical memory not being used by the control system.
/// </summary>
public static ulong RamBytesFree
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[3].Groups[1].Value;
return ulong.Parse(digits);
}
}
/// <summary>
/// Gets the total number of bytes that can be reclaimed.
/// </summary>
public static ulong RamBytesReclaimable
{
get
{
string ramFree = GetRamFree();
string digits = Regex.Matches(ramFree, RAMFREE_DIGITS_REGEX, RegexOptions.Multiline)[4].Groups[1].Value;
return ulong.Parse(digits);
}
}
#endregion
#region Methods
/// <summary>
/// Restarts this program.
/// </summary>
[PublicAPI]
public static void RestartProgram()
{
string consoleResult = string.Empty;
string command = string.Format("progreset -p:{0:D2}", ProgramUtils.ProgramNumber);
CrestronConsole.SendControlSystemCommand(command, ref consoleResult);
}
/// <summary>
/// Reboots the processor.
/// </summary>
[PublicAPI]
public static void Reboot()
{
string consoleResult = string.Empty;
CrestronConsole.SendControlSystemCommand("reboot", ref consoleResult);
}
/// <summary>
/// Runs CrestronInvoke but catches any unhandled exceptions to prevent the program from terminating.
/// http://www.crestronlabs.com/showthread.php?12205-Exception-in-CrestronInvoke-thread-crashes-the-program
/// </summary>
/// <param name="callback"></param>
[PublicAPI]
public static object SafeInvoke(Action callback)
{
return SafeInvoke<object>(unused => callback(), null);
}
/// <summary>
/// Runs CrestronInvoke but catches any unhandled exceptions to prevent the program from terminating.
/// http://www.crestronlabs.com/showthread.php?12205-Exception-in-CrestronInvoke-thread-crashes-the-program
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="callback"></param>
/// <param name="param"></param>
[PublicAPI]
public static object SafeInvoke<T>(Action<T> callback, T param)
{
return CrestronInvoke.BeginInvoke(unused =>
{
try
{
callback(param);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, e.Message);
}
}, null);
}
#endregion
/// <summary>
/// Gets the result from the ramfree console command.
/// </summary>
/// <returns></returns>
private static string GetRamFree()
{
string ramfree = null;
if (!CrestronConsole.SendControlSystemCommand(RAMFREE_COMMAND, ref ramfree))
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
typeof(CrestronUtils).Name, RAMFREE_COMMAND);
}
return ramfree;
}
}
}
#endif

View File

@@ -0,0 +1,400 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using System.Globalization;
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class EnumUtils
{
private static readonly Dictionary<Type, IcdHashSet<object>> s_EnumValuesCache =
new Dictionary<Type, IcdHashSet<object>>();
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <returns></returns>
private static bool IsEnum(Type type)
{
return type == typeof(Enum) || type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsEnum;
}
/// <summary>
/// Returns true if the given type is an enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static bool IsEnum<T>()
{
return IsEnum(typeof(T));
}
#region Values
/// <summary>
/// Gets the underlying value of the enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static object GetUnderlyingValue<T>(T value)
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", value.GetType().Name));
#if SIMPLSHARP
return Convert.ChangeType(value, ToEnum(value).GetTypeCode(), CultureInfo.InvariantCulture);
#else
return Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()));
#endif
}
/// <summary>
/// Gets the values from an enumeration.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValues<T>()
{
return GetValues(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValues(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
// Reflection is slow and this method is called a lot, so we cache the results.
if (!s_EnumValuesCache.ContainsKey(type))
s_EnumValuesCache[type] = GetValuesUncached(type).ToHashSet();
return s_EnumValuesCache[type];
}
/// <summary>
/// Gets the values from an enumeration without performing any caching. This is slow because of reflection.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static IEnumerable<object> GetValuesUncached(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return type
#if SIMPLSHARP
.GetCType()
#else
.GetTypeInfo()
#endif
.GetFields(BindingFlags.Static | BindingFlags.Public)
.Select(x => x.GetValue(null));
}
/// <summary>
/// Gets the 0 value for the given enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetNoneValue<T>()
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return (T)(object)0;
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<T> GetValuesExceptNone<T>()
{
if (!IsEnum(typeof(T)))
throw new InvalidOperationException(string.Format("{0} is not an enum", typeof(T).Name));
return GetValuesExceptNone(typeof(T)).Cast<T>();
}
/// <summary>
/// Gets the values from an enumeration except the 0 value.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<object> GetValuesExceptNone(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return GetValues(type).Where(v => (int)v != 0);
}
#endregion
#region Flags
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static bool IsFlagsEnum<T>()
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return IsFlagsEnum(typeof(T));
}
/// <summary>
/// Returns true if the given enum type has the Flags attribute set.
/// </summary>
/// <returns></returns>
public static bool IsFlagsEnum(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!IsEnum(type))
throw new InvalidOperationException(string.Format("{0} is not an enum", type.Name));
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsDefined(typeof(FlagsAttribute), false);
}
/// <summary>
/// Gets the overlapping values of the given enum flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values"></param>
/// <returns></returns>
public static T GetFlagsIntersection<T>(params T[] values)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
if (values.Length == 0)
return GetNoneValue<T>();
int output = (int)(object)values.First();
foreach (T item in values.Skip(1))
output &= (int)(object)item;
return (T)Enum.ToObject(typeof(T), output);
}
/// <summary>
/// Gets all of the set flags on the given enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return GetValues<T>().Where(e => HasFlag(value, e));
}
/// <summary>
/// Gets all of the set flags on the given enum except 0.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlagsExceptNone<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
T none = GetNoneValue<T>();
return GetFlags(value).Except(none);
}
/// <summary>
/// Gets an enum value of the given type with every flag set.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetFlagsAllValue<T>()
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
int output = GetValues<T>().Aggregate(0, (current, value) => current | (int)(object)value);
return (T)Enum.ToObject(typeof(T), output);
}
/// <summary>
/// Returns true if the enum contains the given flag.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag<T>(T value, T flag)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum(value).HasFlag(ToEnum(flag));
}
/// <summary>
/// Returns true if the enum contains all of the given flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static bool HasFlags<T>(T value, T flags)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum(value).HasFlags(ToEnum(flags));
}
/// <summary>
/// Returns true if only a single flag is set on the given enum value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static bool HasSingleFlag<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return (int)(object)value != (int)(object)GetNoneValue<T>() && !HasMultipleFlags(value);
}
/// <summary>
/// Returns true if the enum has more than 1 flag set.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool HasMultipleFlags<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return HasMultipleFlags((int)(object)value);
}
/// <summary>
/// Returns true if the enum has more than 1 flag set.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static bool HasMultipleFlags(int value)
{
return ((value & (value - 1)) != 0);
}
#endregion
#region Conversion
/// <summary>
/// Shorthand for parsing string to enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
public static T Parse<T>(string data, bool ignoreCase)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
try
{
return (T)Enum.Parse(typeof(T), data, ignoreCase);
}
catch (Exception e)
{
throw new FormatException(
string.Format("Failed to parse {0} as {1}", StringUtils.ToRepresentation(data), typeof(T).Name), e);
}
}
/// <summary>
/// Shorthand for parsing a string to enum. Returns false if the parse failed.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="ignoreCase"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParse<T>(string data, bool ignoreCase, out T result)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
result = default(T);
try
{
result = Parse<T>(data, ignoreCase);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Converts the given enum value to an Enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum<T>(T value)
{
if (!IsEnum<T>())
throw new ArgumentException(string.Format("{0} is not an enum", typeof(T).Name));
return ToEnum((object)value);
}
/// <summary>
/// Converts the given enum value to an Enum.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static Enum ToEnum(object value)
{
return (Enum)value;
}
#endregion
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for working with ICollections.
/// </summary>
public static class CollectionExtensions
{
/// <summary>
/// Removes items matching the predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
public static void RemoveAll<T>(this ICollection<T> extends, Func<T, bool> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
extends.RemoveAll(extends.Where(predicate).ToArray());
}
/// <summary>
/// Removes all of the items from the other collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
public static void RemoveAll<T>(this ICollection<T> extends, IEnumerable<T> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
extends.Remove(item);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for DateTime.
/// </summary>
public static class DateTimeExtensions
{
/// <summary>
/// Gets a string representation of the DateTime with millisecond precision.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string ToLongTimeStringWithMilliseconds(this DateTime extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Todo - Better handle different cultures
return extends.ToString("HH:mm:ss:fff");
}
}
}

View File

@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class DictionaryExtensions
{
/// <summary>
/// Removes the first key with a value matching the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns>False if value is not found in the dictionary.</returns>
[PublicAPI]
public static bool RemoveValue<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
try
{
TKey key = extends.GetKey(value);
return extends.Remove(key);
}
catch (ArgumentOutOfRangeException)
{
return false;
}
}
/// <summary>
/// Removes all keys with the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
[PublicAPI]
public static void RemoveAllValues<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
foreach (TKey key in extends.GetKeys(value).ToArray())
extends.Remove(key);
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise returns default value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
return extends.GetDefault(key, default(TValue));
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise return the default value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key, TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
return extends.ContainsKey(key) ? extends[key] : defaultValue;
}
/// <summary>
/// If the key is present in the dictionary return the value, otherwise add the default value to the dictionary and return it.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetOrAddDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key,
TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
extends[key] = extends.GetDefault(key, defaultValue);
return extends[key];
}
/// <summary>
/// Gets a key for the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException">The value does not exist in the dictionary.</exception>
[PublicAPI]
public static TKey GetKey<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
try
{
return extends.GetKeys(value).First();
}
catch (InvalidOperationException)
{
string message = string.Format("Unable to find Key with Value matching {0}", value);
throw new KeyNotFoundException(message);
}
}
/// <summary>
/// Gets the keys that match the given value.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TKey> GetKeys<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Where(kvp => EqualityComparer<TValue>.Default.Equals(kvp.Value, value))
.Select(kvp => kvp.Key);
}
/// <summary>
/// Updates the dictionary with items from the other dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
[PublicAPI]
public static void Update<TKey, TValue>(this IDictionary<TKey, TValue> extends, IDictionary<TKey, TValue> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
foreach (KeyValuePair<TKey, TValue> pair in other)
extends[pair.Key] = pair.Value;
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="getKey"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TValue> items,
Func<TValue, TKey> getKey)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
if (getKey == null)
throw new ArgumentNullException("getKey");
foreach (TValue item in items)
extends.Add(getKey(item), item);
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="getValue"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TKey> items,
Func<TKey, TValue> getValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
if (getValue == null)
throw new ArgumentNullException("getValue");
foreach (TKey item in items)
extends.Add(item, getValue(item));
}
/// <summary>
/// Adds the sequence of items to the dictionary.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> extends,
IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (KeyValuePair<TKey, TValue> item in items)
extends.Add(item.Key, item.Value);
}
/// <summary>
/// Compares the keys and values of the dictionary to determine equality.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.DictionaryEqual(other, EqualityComparer<TValue>.Default);
}
/// <summary>
/// Compares the keys and values of the dictionary to determine equality.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <param name="valueComparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other,
IEqualityComparer<TValue> valueComparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == other)
return true;
if (other == null)
return false;
if (extends.Count != other.Count)
return false;
foreach (KeyValuePair<TKey, TValue> kvp in extends)
{
TValue secondValue;
if (!other.TryGetValue(kvp.Key, out secondValue))
return false;
if (!valueComparer.Equals(kvp.Value, secondValue))
return false;
}
return true;
}
/// <summary>
/// Returns the KeyValuePairs in key order.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<KeyValuePair<TKey, TValue>> OrderByKey<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(kvp => kvp.Key);
}
/// <summary>
/// Returns a sequence of values ordered by the dictionary keys.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TValue> OrderValuesByKey<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value);
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class EnumExtensions
{
/// <summary>
/// Check to see if a flags enumeration has a specific flag set.
/// </summary>
/// <param name="extends">Flags enumeration to check</param>
/// <param name="value">Flag to check for</param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlag(this Enum extends, Enum value)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (value == null)
throw new ArgumentNullException("value");
if (EnumUtils.HasMultipleFlags(value))
throw new ArgumentException("Value has multiple flags", "value");
return extends.HasFlags(value);
}
/// <summary>
/// Check to see if a flags enumeration has all of the given flags set.
/// </summary>
/// <param name="extends"></param>
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasFlags(this Enum extends, Enum value)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (value == null)
throw new ArgumentNullException("value");
// Not as good as the .NET 4 version of this function, but should be good enough
if (extends.GetType() != value.GetType())
{
string message = string.Format("Enumeration type mismatch. The flag is of type '{0}', was expecting '{1}'.",
value.GetType(), extends.GetType());
throw new ArgumentException(message);
}
ulong num = Convert.ToUInt64(value);
return (Convert.ToUInt64(extends) & num) == num;
}
/// <summary>
/// Casts the enum to the given type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static T Cast<T>(this Enum extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return (T)Enum.ToObject(typeof(T), extends);
}
}
}

View File

@@ -0,0 +1,717 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
namespace ICD.Common.Utils.Extensions
{
public static class EnumerableExtensions
{
/// <summary>
/// Returns the first item in the sequence. Returns the provided default item if there
/// are no elements in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.FirstOrDefault(i => true, defaultItem);
}
/// <summary>
/// Returns the first element in the sequence matching the predicate. Returns the provided
/// default item if there are no elements matching the predicate in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, Func<T, bool> predicate, T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
foreach (T item in extends.Where(predicate))
return item;
return defaultItem;
}
/// <summary>
/// Returns true if there is at least 1 item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirstOrDefault<T>(this IEnumerable<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.TryFirstOrDefault(i => true, out item);
}
/// <summary>
/// Returns true if there is at least 1 item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirstOrDefault<T>(this IEnumerable<T> extends, Func<T, bool> predicate, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
item = default(T);
using (IEnumerator<T> iterator = extends.GetEnumerator())
{
while (iterator.MoveNext())
{
if (!predicate(iterator.Current))
continue;
item = iterator.Current;
return true;
}
}
return false;
}
/// <summary>
/// Returns the true if an element with the given index is in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="index"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool TryElementAt<T>(this IEnumerable<T> extends, int index, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
item = default(T);
if (index < 0)
return false;
T[] itemArray = extends as T[] ?? extends.ToArray();
if (index >= itemArray.Length)
return false;
item = itemArray[index];
return true;
}
/// <summary>
/// Compares two sequences for identical values, ignoring order.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == null)
throw new ArgumentNullException("other");
return extends.ScrambledEquals(other, EqualityComparer<T>.Default);
}
/// <summary>
/// Compares two sequences for identical values, ignoring order.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other, IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends == null)
throw new ArgumentNullException("other");
if (comparer == null)
throw new ArgumentNullException("comparer");
Dictionary<T, int> count = new Dictionary<T, int>(comparer);
foreach (T item in extends)
{
if (count.ContainsKey(item))
count[item]++;
else
count.Add(item, 1);
}
foreach (T item in other)
{
if (count.ContainsKey(item))
count[item]--;
else
return false;
}
return count.Values.All(c => c == 0);
}
/// <summary>
/// Returns the index that matches the predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="match"></param>
/// <returns></returns>
public static int FindIndex<T>(this IEnumerable<T> extends, Predicate<T> match)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (match == null)
throw new ArgumentNullException("match");
int index = 0;
foreach (T item in extends)
{
if (match(item))
return index;
index++;
}
return -1;
}
/// <summary>
/// Allows for selection of multiple results for each item in the sequence.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="extends"></param>
/// <param name="selectors"></param>
/// <returns></returns>
public static IEnumerable<TResult> SelectMulti<TSource, TResult>(this IEnumerable<TSource> extends,
params Func<TSource, TResult>[] selectors)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (selectors == null)
throw new ArgumentNullException("selectors");
return extends.SelectMany(source => selectors, (source, selector) => selector(source));
}
/// <summary>
/// Enumerates each item in the sequence.
/// Useful for processing a LINQ query without creating a new collection.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
[PublicAPI]
public static void Execute<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.ForEach(item => { });
}
/// <summary>
/// Performs the action for each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (action == null)
throw new ArgumentNullException("action");
extends.ForEach((item, index) => action(item));
}
/// <summary>
/// Performs the action for each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T, int> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (action == null)
throw new ArgumentNullException("action");
int index = 0;
foreach (T item in extends)
action(item, index++);
}
#if SIMPLSHARP
/// <summary>
/// Prepends the item to the start of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.PrependMany(new[] {item});
}
#endif
/// <summary>
/// Prepends the items to the start of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> PrependMany<T>(this IEnumerable<T> extends, params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T item in items)
yield return item;
foreach (T each in extends)
yield return each;
}
#if SIMPLSHARP
/// <summary>
/// Appends the item to the end of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Append<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.AppendMany(new[] {item});
}
#endif
/// <summary>
/// Appends the items to the end of the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> AppendMany<T>(this IEnumerable<T> extends, params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T each in extends)
yield return each;
foreach (T item in items)
yield return item;
}
/// <summary>
/// Default ordering for the items in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<T> Order<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OrderBy(i => i);
}
/// <summary>
/// Returns every item in the sequence except the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Except<T>(this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Except(new[] {item});
}
/// <summary>
/// Returns the sequence as a IcdHashSet.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IcdHashSet<T> ToHashSet<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return new IcdHashSet<T>(extends);
}
/// <summary>
/// Returns the sequence as an index:value dictionary.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
Dictionary<int, T> output = new Dictionary<int, T>();
extends.ForEach((item, index) => output.Add(index, item));
return output;
}
/// <summary>
/// Returns the sequence as an index:value dictionary.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<uint, T> ToDictionaryUInt<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
Dictionary<uint, T> output = new Dictionary<uint, T>();
extends.ForEach((item, index) => output.Add((uint)index, item));
return output;
}
/// <summary>
/// Turns an enumerable of KeyValuePairs back into a dictionary
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToDictionary(x => x.Key, x => x.Value);
}
/// <summary>
/// Returns other if the list is empty.
/// Returns other if the list is non-empty and there are two different elements.
/// Returns the element of the list if it is non-empty and all elements are the same.
/// </summary>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static T Unanimous<T>(this IEnumerable<T> extends, T other)
{
if (extends == null)
throw new ArgumentNullException("extends");
T[] array = extends as T[] ?? extends.ToArray();
return array.Unanimous() ? array.First() : other;
}
/// <summary>
/// Returns false if the list is empty.
/// Returns false if the list is non-empty and there are two different elements.
/// Returns true if the list is non-empty and all elements are the same.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool Unanimous<T>(this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
T[] array = extends as T[] ?? extends.ToArray();
if (array.Length == 0)
return false;
T val = array.First();
return array.All(x => EqualityComparer<T>.Default.Equals(x, val));
}
/// <summary>
/// Partitions a sequence into sequences of the given length.
/// </summary>
/// <param name="extends"></param>
/// <param name="partitionSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> extends, int partitionSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
using (IEnumerator<T> enumerator = extends.GetEnumerator())
{
while (enumerator.MoveNext())
yield return YieldBatchElements(enumerator, partitionSize - 1);
}
}
private static IEnumerable<T> YieldBatchElements<T>(IEnumerator<T> source, int partitionSize)
{
if (source == null)
throw new ArgumentNullException("source");
// Important to enumerate through partitionSize items before returning
// Otherwise enumerable.Partition(3).Skip(1) will do unwanted things.
List<T> output = new List<T> {source.Current};
for (int i = 0; i < partitionSize && source.MoveNext(); i++)
output.Add(source.Current);
return output;
}
/// <summary>
/// Returns the minimal element of the given sequence, based on
/// the given projection.
/// </summary>
/// <remarks>
/// If more than one element has the minimal projected value, the first
/// one encountered will be returned. This overload uses the default comparer
/// for the projected type. This operator uses immediate execution, but
/// only buffers a single result (the current minimal element).
/// </remarks>
/// <typeparam name="TSource">Type of the source sequence</typeparam>
/// <typeparam name="TKey">Type of the projected element</typeparam>
/// <param name="source">Source sequence</param>
/// <param name="selector">Selector to use to pick the results to compare</param>
/// <returns>The minimal element, according to the projection.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector)
{
if (source == null)
throw new ArgumentNullException("source");
if (selector == null)
throw new ArgumentNullException("selector");
return source.MinBy(selector, Comparer<TKey>.Default);
}
/// <summary>
/// Returns the minimal element of the given sequence, based on
/// the given projection and the specified comparer for projected values.
/// </summary>
/// <remarks>
/// If more than one element has the minimal projected value, the first
/// one encountered will be returned. This operator uses immediate execution, but
/// only buffers a single result (the current minimal element).
/// </remarks>
/// <typeparam name="TSource">Type of the source sequence</typeparam>
/// <typeparam name="TKey">Type of the projected element</typeparam>
/// <param name="source">Source sequence</param>
/// <param name="selector">Selector to use to pick the results to compare</param>
/// <param name="comparer">Comparer to use to compare projected values</param>
/// <returns>The minimal element, according to the projection.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/>, <paramref name="selector"/>
/// or <paramref name="comparer"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector,
IComparer<TKey> comparer)
{
if (source == null)
throw new ArgumentNullException("source");
if (selector == null)
throw new ArgumentNullException("selector");
if (comparer == null)
throw new ArgumentNullException("comparer");
using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
throw new InvalidOperationException("Sequence contains no elements");
TSource min = sourceIterator.Current;
TKey minKey = selector(min);
while (sourceIterator.MoveNext())
{
TSource candidate = sourceIterator.Current;
TKey candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) >= 0)
continue;
min = candidate;
minKey = candidateProjected;
}
return min;
}
}
/// <summary>
/// Removes any null elements from an enumerable of nullable value types
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> ExceptNulls<T>(this IEnumerable<T?> extends)
where T : struct
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.Where(e => e.HasValue).Select(e => e.Value);
}
/// <summary>
/// Computes the sum of a sequence of byte values.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static byte Sum(this IEnumerable<byte> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return (byte)extends.Select(i => (int)i).Sum();
}
/// <summary>
/// Skips duplicate, consecutive items.
/// E.g.
/// [1, 2, 2, 3, 1, 1]
/// Becomes
/// [1, 2, 3, 1]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return Consolidate(extends, Comparer<T>.Default);
}
/// <summary>
/// Skips duplicate, consecutive items.
/// E.g.
/// [1, 2, 2, 3, 1, 1]
/// Becomes
/// [1, 2, 3, 1]
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(IEnumerable<T> extends, IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
bool first = true;
T last = default(T);
foreach (T item in extends)
{
if (!first && comparer.Compare(last, item) != 0)
continue;
first = false;
last = item;
yield return item;
}
}
/// <summary>
/// Returns true if all items in the sequence match the predicate.
/// Returns false if the sequence is empty.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="predicate"></param>
/// <returns></returns>
[PublicAPI]
public static bool AnyAndAll<T>(this IEnumerable<T> extends, Func<T, bool> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
bool any = false;
foreach (T item in extends)
{
any = true;
if (!predicate(item))
return false;
}
return any;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for EventHandlers.
/// </summary>
public static class EventHandlerExtensions
{
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
public static void Raise(this EventHandler extends, object sender)
{
if (extends != null)
extends(sender, EventArgs.Empty);
}
/// <summary>
/// Raises the event safely. Simply skips if the handler is null.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="args"></param>
public static void Raise<T>(this EventHandler<T> extends, object sender, T args)
where T : EventArgs
{
if (extends != null)
extends(sender, args);
}
}
}

View File

@@ -0,0 +1,87 @@
#if STANDARD
using ICD.Common.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ICD.NetStandard.Common.Utils.Extensions
{
public static class HashSetExtensions
{
[PublicAPI]
public static HashSet<T> Subtract<T>(this HashSet<T> extends, IEnumerable<T> set)
{
HashSet<T> subtractSet = new HashSet<T>(extends);
if (set == null)
return subtractSet;
foreach (T item in set)
subtractSet.Remove(item);
return subtractSet;
}
[PublicAPI]
public static bool IsSubsetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
return extends.All(setToCompare.Contains);
}
[PublicAPI]
public static HashSet<T> Intersection<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> intersectionSet = new HashSet<T>();
if (set == null)
return intersectionSet;
foreach (T item in extends.Where(set.Contains))
intersectionSet.Add(item);
foreach (T item in set.Where(extends.Contains))
intersectionSet.Add(item);
return intersectionSet;
}
/// <summary>
/// Returns items that are not common between both sets.
/// </summary>
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public static HashSet<T> NonIntersection<T>(this HashSet<T> extends, HashSet<T> set)
{
return new HashSet<T>(extends.Subtract(set).Union(set.Subtract(extends)));
}
[PublicAPI]
public static bool IsProperSubsetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
// Is a proper subset if A is a subset of B and A != B
return (extends.IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(extends));
}
[PublicAPI]
public static bool IsSupersetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
return setToCompare.IsSubsetOf(extends);
}
[PublicAPI]
public static bool IsProperSupersetOf<T>(this HashSet<T> extends, HashSet<T> set)
{
HashSet<T> setToCompare = set ?? new HashSet<T>();
// B is a proper superset of A if B is a superset of A and A != B
return (extends.IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(extends));
}
}
}
#endif

View File

@@ -0,0 +1,107 @@
using System;
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>
/// 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)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.String)
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
return (T)(object)extends.GetValueAsInt();
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils.Extensions
{
public static class QueueExtensions
{
/// <summary>
/// Enqueues each item in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
public static void EnqueueRange<T>(this Queue<T> extends, IEnumerable<T> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
foreach (T item in items)
extends.Enqueue(item);
}
/// <summary>
/// Dequeues 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 Dequeue<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.Dequeue();
return true;
}
}
}

View File

@@ -0,0 +1,32 @@
#if SIMPLSHARP
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp.Reflection;
namespace ICD.Common.Utils.Extensions
{
/// <summary>
/// Extension methods for use with reflection objects.
/// </summary>
public static class ReflectionExtensions
{
/// <summary>
/// Returns the custom attributes attached to the member.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this MemberInfo extends, bool inherits)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetCustomAttributes(typeof(T), inherits).Cast<T>();
}
}
}
#endif

View File

@@ -0,0 +1,36 @@
using System;
using System.Text;
namespace ICD.Common.Utils.Extensions
{
public static class StringBuilderExtensions
{
/// <summary>
/// Empties the StringBuilder.
/// </summary>
/// <param name="extends"></param>
public static void Clear(this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.Remove(0, extends.Length);
}
/// <summary>
/// Returns the current string value of the StringBuilder and clears the
/// StringBuilder for further use.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string Pop(this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string output = extends.ToString();
extends.Clear();
return output;
}
}
}

View File

@@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
public static class StringExtensions
{
/// <summary>
/// Returns the first appearance of an item from the given sequence.
/// </summary>
/// <param name="extends"></param>
/// <param name="items"></param>
/// <param name="first"></param>
/// <returns></returns>
[PublicAPI]
public static int IndexOf(this string extends, IEnumerable<string> items, out string first)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (items == null)
throw new ArgumentNullException("items");
int index = -1;
first = null;
foreach (string item in items)
{
int thisIndex = extends.IndexOf(item, StringComparison.Ordinal);
if (thisIndex == -1)
continue;
if (index != -1 && thisIndex >= index)
continue;
index = thisIndex;
first = item;
}
return index;
}
/// <summary>
/// Returns true if the string starts with the given character.
/// </summary>
/// <param name="extends"></param>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool StartsWith(this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.StartsWith(character.ToString());
}
/// <summary>
/// Returns true if the string ends with the given character.
/// </summary>
/// <param name="extends"></param>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool EndsWith(this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.EndsWith(character.ToString());
}
/// <summary>
/// Splits the string by the given delimiter, returning up to the given number of substrings.
/// E.g. "a:b:c".Split(':', 2) returns ["a", "b:c"]
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeter"></param>
/// <param name="count"></param>
/// <returns></returns>
public static IEnumerable<string> Split(this string extends, char delimeter, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (count < 2)
{
yield return extends;
yield break;
}
int index = extends.IndexOf(delimeter);
if (index < 0)
{
yield return extends;
yield break;
}
string first = extends.Substring(0, index);
string second = extends.Substring(index + 1);
count--;
yield return first;
foreach (string item in second.Split(delimeter, count))
yield return item;
}
/// <summary>
/// Splits a string into chunks of the given length.
/// </summary>
/// <param name="extends"></param>
/// <param name="chunkSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, int chunkSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (chunkSize <= 0)
throw new InvalidOperationException("chunkSize must be greater than 0");
return Enumerable.Range(0, extends.Length / chunkSize)
.Select(i => extends.Substring(i * chunkSize, chunkSize));
}
/// <summary>
/// Splits a string by a given substring.
/// Taken from
/// https://social.msdn.microsoft.com/Forums/en-US/914a350f-e0e9-45e0-91a4-6b4b2168e780/string-split-function
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeter"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, string delimeter)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (delimeter == null)
throw new ArgumentNullException("delimeter");
int dSum = 0;
int sSum = 0;
int length = extends.Length;
int delimiterLength = delimeter.Length;
if (delimiterLength == 0 || length == 0 || length < delimiterLength)
{
yield return extends;
yield break;
}
char[] cd = delimeter.ToCharArray();
char[] cs = extends.ToCharArray();
for (int i = 0; i < delimiterLength; i++)
{
dSum += cd[i];
sSum += cs[i];
}
int start = 0;
for (int i = start; i < length - delimiterLength; i++)
{
if (i >= start && dSum == sSum && extends.Substring(i, delimiterLength) == delimeter)
{
yield return extends.Substring(start, i - start);
start = i + delimiterLength;
}
sSum += cs[i + delimiterLength] - cs[i];
}
if (dSum == sSum && extends.Substring(length - delimiterLength, delimiterLength) == delimeter)
{
yield return extends.Substring(start, length - delimiterLength - start);
yield return string.Empty;
}
else
yield return extends.Substring(start, length - start);
}
/// <summary>
/// Splits a string by the given substrings.
/// </summary>
/// <param name="extends"></param>
/// <param name="delimeters"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, IEnumerable<string> delimeters)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (delimeters == null)
throw new ArgumentNullException("delimeters");
string[] delimitersArray = delimeters as string[] ?? delimeters.ToArray();
return delimitersArray.Length == 0
? new[] {extends}
: extends.Split(delimitersArray.First())
.SelectMany(s => s.Split(delimitersArray.Skip(1)))
.Where(s => !string.IsNullOrEmpty(s));
}
/// <summary>
/// Removes whitespace from the string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string RemoveWhitespace(this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return new string(extends.Where(c => !Char.IsWhiteSpace(c)).ToArray());
}
/// <summary>
/// Removes the given characters from the string.
/// </summary>
/// <param name="extends"></param>
/// <param name="characters"></param>
/// <returns></returns>
[PublicAPI]
public static string Remove(this string extends, IEnumerable<char> characters)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (characters == null)
throw new ArgumentNullException("characters");
return new string(extends.Where(c => !characters.Contains(c)).ToArray());
}
/// <summary>
/// Returns true if the string only contains numbers.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool IsNumeric(this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.All(char.IsDigit);
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Text;
namespace ICD.Common.Utils.Extensions
{
public static class TimeSpanExtensions
{
public static string ToReadableString(this TimeSpan extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
StringBuilder builder = new StringBuilder();
if (extends.Days > 0)
builder.AppendFormat("{0} days, ", extends.Days);
if (extends.Hours > 0)
builder.AppendFormat("{0} hours, ", extends.Hours);
if (extends.Minutes > 0)
builder.AppendFormat("{0} minutes, ", extends.Minutes);
if (extends.Seconds > 0)
builder.AppendFormat("{0} seconds, ", extends.Seconds);
if (extends.Milliseconds > 0)
{
builder.AppendFormat("{0}.{1} ms", extends.Milliseconds,
((double)extends.Ticks / TimeSpan.TicksPerMillisecond) - extends.TotalMilliseconds);
}
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Reflection;
#endif
namespace ICD.Common.Utils.Extensions
{
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type from, Type to)
{
return to.IsAssignableFrom(from);
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public static class IcdDirectory
{
public static string GetApplicationDirectory()
{
#if SIMPLSHARP
return Directory.GetApplicationDirectory();
#else
return Directory.GetCurrentDirectory();
#endif
}
public static bool Exists(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.Exists(path);
}
public static string[] GetFiles(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetFiles(path);
}
public static string[] GetDirectories(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetDirectories(path);
}
public static void Delete(string path, bool recursive)
{
if (path == null)
throw new ArgumentNullException("path");
Directory.Delete(path, recursive);
}
public static void CreateDirectory(string path)
{
if (path == null)
throw new ArgumentNullException("path");
Directory.CreateDirectory(path);
}
public static string GetDirectoryRoot(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Directory.GetDirectoryRoot(path);
}
}
}

View File

@@ -0,0 +1,39 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
using System;
using System.Text;
namespace ICD.Common.Utils.IO
{
public sealed class IcdEncodingStringWriter : IcdStringWriter
{
public IcdEncodingStringWriter(StringBuilder output, Encoding encoding)
: base(new EncodingStringWriter(output, encoding))
{
}
private sealed class EncodingStringWriter : StringWriter
{
private readonly Encoding m_Encoding;
public override Encoding Encoding { get { return m_Encoding; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="builder"></param>
/// <param name="encoding"></param>
public EncodingStringWriter(StringBuilder builder, Encoding encoding)
: base(builder)
{
if (encoding == null)
throw new ArgumentNullException("encoding");
m_Encoding = encoding;
}
}
}
}

View File

@@ -0,0 +1,60 @@
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
using System;
using System.Text;
namespace ICD.Common.Utils.IO
{
public static class IcdFile
{
[PublicAPI]
public static string ReadToEnd(string path, Encoding encoding)
{
if (path == null)
throw new ArgumentNullException("path");
if (encoding == null)
throw new ArgumentNullException("encoding");
#if SIMPLSHARP
return File.ReadToEnd(path, encoding);
#else
return File.ReadAllText(path, encoding);
#endif
}
[PublicAPI]
public static bool Exists(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return File.Exists(path);
}
[PublicAPI]
public static void Copy(string pathFrom, string pathTo)
{
if (pathFrom == null)
throw new ArgumentNullException("pathFrom");
if (pathTo == null)
throw new ArgumentNullException("pathTo");
File.Copy(pathFrom, pathTo);
}
[PublicAPI]
public static void Delete(string path)
{
if (path == null)
throw new ArgumentNullException("path");
File.Delete(path);
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdFileStream : IcdStream
{
public int Position { get; set; }
public FileStream WrappedFileStream { get { return WrappedStream as FileStream; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="fileStrean"></param>
public IcdFileStream(FileStream fileStrean)
: base(fileStrean)
{
}
public static IcdFileStream OpenWrite(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return new IcdFileStream(File.OpenWrite(path));
}
public void Flush()
{
WrappedFileStream.Flush();
}
public void Close()
{
#if SIMPLSHARP
WrappedFileStream.Close();
#else
WrappedFileStream.Dispose();
#endif
}
}
}

View File

@@ -0,0 +1,47 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdMemoryStream : IcdStream
{
public int Position { get; set; }
public MemoryStream WrappedMemoryStream { get { return WrappedStream as MemoryStream; } }
/// <summary>
/// Constructor.
/// </summary>
public IcdMemoryStream()
: this(new MemoryStream())
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="memoryStream"></param>
public IcdMemoryStream(MemoryStream memoryStream)
: base(memoryStream)
{
}
public void Flush()
{
WrappedMemoryStream.Flush();
}
public void Close()
{
#if SIMPLSHARP
WrappedMemoryStream.Close();
#else
WrappedMemoryStream.Dispose();
#endif
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public static class IcdPath
{
public static string GetFileNameWithoutExtension(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetFileNameWithoutExtension(path);
}
public static string GetDirectoryName(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetDirectoryName(path);
}
public static string GetExtension(string path)
{
if (path == null)
throw new ArgumentNullException("path");
return Path.GetExtension(path);
}
public static string Combine(string a, string b)
{
if (a == null)
throw new ArgumentNullException("a");
if (b == null)
throw new ArgumentNullException("b");
return Path.Combine(a, b);
}
public static string ChangeExtension(string path, string ext)
{
if (path == null)
throw new ArgumentNullException("path");
if (ext == null)
throw new ArgumentNullException("ext");
return Path.ChangeExtension(path, ext);
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdStream : IDisposable
{
private readonly Stream m_Stream;
public Stream WrappedStream { get { return m_Stream; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
public IcdStream(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
m_Stream = stream;
}
public void Dispose()
{
m_Stream.Dispose();
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#elif STANDARD
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdStreamReader : IDisposable
{
private readonly StreamReader m_StreamReader;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="memoryStream"></param>
public IcdStreamReader(IcdMemoryStream memoryStream)
{
if (memoryStream == null)
throw new ArgumentNullException("memoryStream");
m_StreamReader = new StreamReader(memoryStream.WrappedMemoryStream);
}
~IcdStreamReader()
{
Dispose();
}
public string ReadToEnd()
{
return m_StreamReader.ReadToEnd();
}
public void Dispose()
{
m_StreamReader.Dispose();
}
}
}

View File

@@ -0,0 +1,24 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdStringReader : IcdTextReader
{
public StringReader WrappedStringReader { get { return WrappedTextReader as StringReader; } }
public IcdStringReader(string value)
: this(new StringReader(value))
{
}
private IcdStringReader(StringReader stringReader)
: base(stringReader)
{
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Text;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdStringWriter : IcdTextWriter
{
public StringWriter WrappedStringWriter { get { return WrappedTextWriter as StringWriter; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stringWriter"></param>
public IcdStringWriter(StringWriter stringWriter)
: base(stringWriter)
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stringBuilder"></param>
public IcdStringWriter(StringBuilder stringBuilder)
: this(new StringWriter(stringBuilder))
{
}
}
}

View File

@@ -0,0 +1,21 @@
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdTextReader
{
private readonly TextReader m_TextReader;
public TextReader WrappedTextReader { get { return m_TextReader; } }
protected IcdTextReader(TextReader textReader)
{
m_TextReader = textReader;
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public class IcdTextWriter : IDisposable
{
private readonly TextWriter m_TextWriter;
public TextWriter WrappedTextWriter { get { return m_TextWriter; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
protected IcdTextWriter(TextWriter textWriter)
{
if (textWriter == null)
throw new ArgumentNullException("textWriter");
m_TextWriter = textWriter;
}
~IcdTextWriter()
{
Dispose();
}
public void Dispose()
{
m_TextWriter.Dispose();
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace ICD.Common.Utils
{
/// <summary>
/// Provides features for managing the disposed state of an IDisposable.
/// </summary>
public interface IStateDisposable : IDisposable
{
/// <summary>
/// Returns true if this instance has been disposed.
/// </summary>
bool IsDisposed { get; }
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if SIMPLSHARP
using Crestron.SimplSharp;
#endif
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public sealed class IcdConsole
{
public enum eAccessLevel
{
Operator = 0,
Programmer = 1,
Administrator = 2
}
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
[PublicAPI]
public static void ConsoleCommandResponseLine(string message, params object[] args)
{
ConsoleCommandResponse(message + IcdEnvironment.NewLine, args);
}
/// <summary>
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
[PublicAPI]
public static void ConsoleCommandResponse(string message, params object[] args)
{
message = string.Format(message, args);
#if SIMPLSHARP
try
{
CrestronConsole.ConsoleCommandResponse(message);
}
catch (NotSupportedException)
{
CrestronConsole.Print(message);
}
#else
System.Console.Write(message, args);
#endif
}
public static void PrintLine(string message)
{
#if SIMPLSHARP
CrestronConsole.PrintLine(message);
#else
System.Console.WriteLine(message);
#endif
}
public static void PrintLine(string message, params object[] args)
{
#if SIMPLSHARP
CrestronConsole.PrintLine(message, args);
#else
System.Console.WriteLine(message, args);
#endif
}
public static void Print(string message)
{
#if SIMPLSHARP
CrestronConsole.Print(message);
#else
System.Console.Write(message);
#endif
}
public static void Print(string message, params object[] args)
{
#if SIMPLSHARP
CrestronConsole.Print(message, args);
#else
System.Console.Write(message, args);
#endif
}
public static bool SendControlSystemCommand(string command, ref string result)
{
#if SIMPLSHARP
return CrestronConsole.SendControlSystemCommand(command, ref result);
#else
result = string.Empty;
return false;
#endif
}
public static void AddNewConsoleCommand(Action<string> callback, string command, string help, eAccessLevel accessLevel)
{
#if SIMPLSHARP
CrestronConsole.AddNewConsoleCommand(str => callback(str), command, help, (ConsoleAccessLevelEnum)(int)accessLevel);
#endif
}
}
}

View File

@@ -0,0 +1,118 @@
#if SIMPLSHARP
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
public static string NewLine { get { return CrestronEnvironment.NewLine; } }
public static eRuntimeEnvironment RuntimeEnvironment
{
get { return GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment); }
}
/// <summary>
/// Static constructor.
/// </summary>
static IcdEnvironment()
{
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironmentOnProgramStatusEventHandler;
CrestronEnvironment.EthernetEventHandler += CrestronEnvironmentOnEthernetEventHandler;
}
/// <summary>
/// Gets the network address(es) of the processor.
/// </summary>
[PublicAPI]
public static IEnumerable<string> NetworkAddresses
{
get
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
}
}
#region Methods
public static DateTime GetLocalTime()
{
return CrestronEnvironment.GetLocalTime();
}
public static eEthernetEventType GetEthernetEventType(Crestron.SimplSharp.eEthernetEventType type)
{
switch (type)
{
case Crestron.SimplSharp.eEthernetEventType.LinkDown:
return eEthernetEventType.LinkDown;
case Crestron.SimplSharp.eEthernetEventType.LinkUp:
return eEthernetEventType.LinkUp;
default:
throw new ArgumentOutOfRangeException("type");
}
}
public static eEthernetAdapterType GetEthernetAdapterType(EthernetAdapterType ethernetAdapter)
{
return (eEthernetAdapterType)(int)ethernetAdapter;
}
public static eProgramStatusEventType GetProgramStatusEventType(Crestron.SimplSharp.eProgramStatusEventType type)
{
switch (type)
{
case Crestron.SimplSharp.eProgramStatusEventType.Stopping:
return eProgramStatusEventType.Stopping;
case Crestron.SimplSharp.eProgramStatusEventType.Paused:
return eProgramStatusEventType.Paused;
case Crestron.SimplSharp.eProgramStatusEventType.Resumed:
return eProgramStatusEventType.Resumed;
default:
throw new ArgumentOutOfRangeException("type");
}
}
public static eRuntimeEnvironment GetRuntimeEnvironment(Crestron.SimplSharp.eRuntimeEnvironment runtimeEnvironment)
{
switch (runtimeEnvironment)
{
case Crestron.SimplSharp.eRuntimeEnvironment.SIMPL:
return eRuntimeEnvironment.SimplSharp;
case Crestron.SimplSharp.eRuntimeEnvironment.SimplSharpPro:
return eRuntimeEnvironment.SimplSharpPro;
default:
throw new ArgumentOutOfRangeException("runtimeEnvironment");
}
}
#endregion
#region Private Methods
private static void CrestronEnvironmentOnEthernetEventHandler(EthernetEventArgs args)
{
EthernetEventCallback handler = OnEthernetEvent;
if (handler != null)
handler(GetEthernetAdapterType(args.EthernetAdapter), GetEthernetEventType(args.EthernetEventType));
}
private static void CrestronEnvironmentOnProgramStatusEventHandler(Crestron.SimplSharp.eProgramStatusEventType type)
{
ProgramStatusCallback handler = OnProgramStatusEvent;
if (handler != null)
handler(GetProgramStatusEventType(type));
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,34 @@
#if STANDARD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
public static string NewLine { get { return Environment.NewLine; } }
public static DateTime GetLocalTime()
{
return DateTime.Now;
}
public static eRuntimeEnvironment RuntimeEnvironment { get { return eRuntimeEnvironment.Standard; } }
public static IEnumerable<string> NetworkAddresses
{
get
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.SelectMany(ni => ni.GetIPProperties().UnicastAddresses
.Where(ua => ua.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(ua => ua.Address.ToString()));
}
}
}
}
#endif

View File

@@ -0,0 +1,57 @@
using System;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
/// <summary>
/// Enumeration to define the various runtime environments a SIMPL# module can run in.
/// </summary>
public enum eRuntimeEnvironment
{
SimplSharp,
SimplSharpPro,
Standard
}
/// <summary>
/// Enum for the Program Event Types
/// </summary>
public enum eProgramStatusEventType
{
Stopping,
Paused,
Resumed,
}
/// <summary>
/// Enum for the Ethernet Event Types
/// </summary>
public enum eEthernetEventType
{
LinkDown,
LinkUp,
}
/// <summary>
/// Enums for the Ethernet Adapter Type
/// </summary>
[Flags]
public enum eEthernetAdapterType
{
EthernetUnknownAdapter = 0,
EthernetLanAdapter = 1,
EthernetCsAdapter = 2,
EthernetWifiAdapter = 4,
EthernetLan2Adapter = 8,
}
public delegate void ProgramStatusCallback(eProgramStatusEventType type);
public delegate void EthernetEventCallback(eEthernetAdapterType adapter, eEthernetEventType type);
public static event ProgramStatusCallback OnProgramStatusEvent;
public static event EthernetEventCallback OnEthernetEvent;
}
}

View File

@@ -0,0 +1,210 @@
using System;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
public static class IcdErrorLog
{
private const string CONSOLE_RED = "\x1B[31;1m";
private const string CONSOLE_GREEN = "\x1B[32;1m";
private const string CONSOLE_YELLOW = "\x1B[33;1m";
private const string CONSOLE_BLUE = "\x1B[34;1m";
//private const string CONSOLE_MAGENTA = "\x1B[35;1m";
private const string CONSOLE_CYAN = "\x1B[36;1m";
//private const string CONSOLE_WHITE = "\x1B[37;1m";
private const string CONSOLE_YELLOW_ON_RED_BACKGROUND = "\x1B[93;41m";
private const string CONSOLE_RESET = "\x1B[0m";
private static readonly SafeCriticalSection s_LoggingSection;
/// <summary>
/// Static constructor.
/// </summary>
static IcdErrorLog()
{
s_LoggingSection = new SafeCriticalSection();
}
[PublicAPI]
public static void Error(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_RED);
Crestron.SimplSharp.ErrorLog.Error(message);
#else
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Error(string message, params object[] args)
{
Error(string.Format(message, args));
}
[PublicAPI]
public static void Warn(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_YELLOW);
Crestron.SimplSharp.ErrorLog.Warn(message);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Warn(string message, params object[] args)
{
Warn(string.Format(message, args));
}
[PublicAPI]
public static void Notice(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_BLUE);
Crestron.SimplSharp.ErrorLog.Notice(message);
#else
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Notice(string message, params object[] args)
{
Notice(string.Format(message, args));
}
[PublicAPI]
public static void Ok(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_GREEN);
Crestron.SimplSharp.ErrorLog.Ok(message);
#else
System.Console.ForegroundColor = ConsoleColor.Green;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Ok(string message, params object[] args)
{
Ok(string.Format(message, args));
}
[PublicAPI]
public static void Exception(Exception ex, string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_YELLOW_ON_RED_BACKGROUND);
Crestron.SimplSharp.ErrorLog.Exception(message, ex);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.BackgroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
System.Console.ResetColor();
System.Console.Error.WriteLine(ex.StackTrace);
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Exception(Exception ex, string message, params object[] args)
{
message = string.Format(message, args);
Exception(ex, message);
}
[PublicAPI]
public static void Info(string message)
{
s_LoggingSection.Enter();
try
{
#if SIMPLSHARP
message = FormatConsoleColor(message, CONSOLE_CYAN);
Crestron.SimplSharp.ErrorLog.Info(message);
#else
System.Console.ForegroundColor = ConsoleColor.Cyan;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
#endif
}
finally
{
s_LoggingSection.Leave();
}
}
[PublicAPI]
public static void Info(string message, params object[] args)
{
Info(string.Format(message, args));
}
/// <summary>
/// Formats the text with the given console color.
/// </summary>
/// <param name="text"></param>
/// <param name="color"></param>
/// <returns></returns>
private static string FormatConsoleColor(string text, string color)
{
return string.Format("{0}{1}{2}", color, text, CONSOLE_RESET);
}
}
}

View File

@@ -0,0 +1,40 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System;
using System.IO.Compression;
#endif
namespace ICD.Common.Utils
{
/// <summary>
/// Utils for managing archives.
/// </summary>
public static class IcdZip
{
/// <summary>
/// Unzips the archive at the given path.
/// </summary>
/// <param name="path"></param>
/// <param name="outputPath"></param>
public static bool Unzip(string path, string outputPath)
{
#if SIMPLSHARP
return CrestronZIP.Unzip(path, outputPath) == CrestronZIP.ResultCode.ZR_OK;
#else
try
{
using (ZipArchive archive = ZipFile.Open(path, ZipArchiveMode.Read))
archive.ExtractToDirectory(outputPath);
}
catch (Exception)
{
return false;
}
return true;
#endif
}
}
}

View File

@@ -0,0 +1,78 @@
using System;
using ICD.Common.Properties;
using Newtonsoft.Json;
namespace ICD.Common.Utils.Json
{
public abstract class AbstractGenericJsonConverter<T> : JsonConverter
{
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public override sealed void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
WriteJson(writer, (T)value, serializer);
}
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
[PublicAPI]
public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer);
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
public override sealed object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
return ReadJson(reader, (T)existingValue, serializer);
}
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
/// <param name="existingValue">The existing value of object being read.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>
/// The object value.
/// </returns>
[PublicAPI]
public abstract T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer);
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ICD.Common.Utils.Json
{
/// <summary>
/// Simple wrapper for serialization of an object and its type.
/// </summary>
public sealed class JsonItemWrapper
{
private const string TYPE_TOKEN = "t";
private const string ITEM_TOKEN = "i";
private readonly string m_ItemTypeString;
private readonly object m_Item;
/// <summary>
/// Gets the string representation of the item type. Returns null if the item is null.
/// </summary>
public string ItemTypeString { get { return m_ItemTypeString; } }
/// <summary>
/// Gets the Type of the item. Returns null if the item is null.
/// </summary>
public Type ItemType
{
get { return string.IsNullOrEmpty(m_ItemTypeString) ? null : Type.GetType(m_ItemTypeString); }
}
/// <summary>
/// Gets the wrapped item.
/// </summary>
public object Item { get { return string.IsNullOrEmpty(m_ItemTypeString) ? null : m_Item; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="item"></param>
public JsonItemWrapper(object item)
{
m_ItemTypeString = item == null ? null : item.GetType().FullName;
m_Item = item;
}
/// <summary>
/// Writes the JsonItemWrapper as a JObject.
/// </summary>
/// <param name="writer"></param>
public void Write(JsonWriter writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
writer.WriteStartObject();
writer.WritePropertyName(TYPE_TOKEN);
writer.WriteValue(m_ItemTypeString);
writer.WritePropertyName(ITEM_TOKEN);
writer.WriteValue(JsonConvert.SerializeObject(m_Item));
writer.WriteEndObject();
}
/// <summary>
/// Reads the JToken back to the wrapped object.
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public static object ReadToObject(JToken token)
{
if (token == null)
throw new ArgumentNullException("token");
string typeString = (string)token.SelectToken(TYPE_TOKEN);
if (string.IsNullOrEmpty(typeString))
return null;
string itemString = (string)token.SelectToken(ITEM_TOKEN);
Type type = Type.GetType(typeString);
return JsonConvert.DeserializeObject(itemString, type);
}
}
}

View File

@@ -0,0 +1,79 @@
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Json
{
/// <summary>
/// Utility methods for working with JSON.
/// </summary>
[PublicAPI]
public static class JsonUtils
{
/// <summary>
/// Pretty-prints the JSON document.
/// </summary>
/// <param name="json"></param>
[PublicAPI]
public static void Print(string json)
{
int indent = 0;
bool quoted = false;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < json.Length; i++)
{
char ch = json[i];
switch (ch)
{
case '{':
case '[':
sb.Append(ch);
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, ++indent).ForEach(item => sb.Append('\t'));
}
break;
case '}':
case ']':
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, --indent).ForEach(item => sb.Append('\t'));
}
sb.Append(ch);
break;
case '"':
sb.Append(ch);
bool escaped = false;
int index = i;
while (index > 0 && json[--index] == '\\')
escaped = !escaped;
if (!escaped)
quoted = !quoted;
break;
case ',':
sb.Append(ch);
if (!quoted)
{
sb.Append(IcdEnvironment.NewLine);
Enumerable.Range(0, indent).ForEach(item => sb.Append('\t'));
}
break;
case ':':
sb.Append(ch);
if (!quoted)
sb.Append(" ");
break;
default:
sb.Append(ch);
break;
}
}
IcdConsole.PrintLine(sb.ToString());
}
}
}

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Collections;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// Utility methods for math operations.
/// </summary>
public static class MathUtils
{
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static int Clamp(int number, int min, int max)
{
return (int)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static ushort Clamp(ushort number, ushort min, ushort max)
{
return (ushort)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static float Clamp(float number, float min, float max)
{
return (float)Clamp((double)number, min, max);
}
/// <summary>
/// Clamps the number between the two values.
/// </summary>
/// <param name="number"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static double Clamp(double number, double min, double max)
{
return min < max
? Math.Min(Math.Max(number, min), max)
: Math.Min(Math.Max(number, max), min);
}
/// <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 double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value)
{
double 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 float MapRange(float inputStart, float inputEnd, float outputStart, float outputEnd, float value)
{
return (float)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 int MapRange(int inputStart, int inputEnd, int outputStart, int outputEnd, int value)
{
return (int)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 ushort MapRange(ushort inputStart, ushort inputEnd, ushort outputStart, ushort outputEnd, ushort value)
{
return (ushort)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value);
}
/// <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.
/// less than 0.0f - the date is before the start.
/// greater than 1.0f - the date is after the end.
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="value"></param>
/// <returns></returns>
public static double MapRange(DateTime start, DateTime end, DateTime value)
{
return MapRange(new TimeSpan(start.Ticks).TotalSeconds,
new TimeSpan(end.Ticks).TotalSeconds,
0.0f, 1.0f, new TimeSpan(value.Ticks).TotalSeconds);
}
/// <summary>
/// Gets the digit count for the given number.
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static int GetNumberOfDigits(int number)
{
int output = number.ToString().Length;
if (number < 0)
output--;
return output;
}
/// <summary>
/// Gets the digit count for the given number.
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static int GetNumberOfDigits(uint number)
{
return number.ToString().Length;
}
/// <summary>
/// Takes a sequence of numbers:
/// 1, 3, 5, 6, 7, 8, 9, 10, 12
/// And calculates the continuous ranges:
/// (1, 1), (3, 3), (5, 10), (12, 12)
/// </summary>
public static IEnumerable<int[]> GetRanges(IEnumerable<int> numbers)
{
if (numbers == null)
throw new ArgumentNullException("numbers");
int[] currentRange = null;
foreach (int number in numbers.Order())
{
if (currentRange == null)
currentRange = new[] {number, number};
else if (currentRange[1] == number - 1)
currentRange = new[] {currentRange[0], number};
else
{
yield return currentRange;
currentRange = new[] {number, number};
}
}
if (currentRange != null)
yield return currentRange;
}
/// <summary>
/// Rounds the given number to the nearest item in the given sequence.
/// </summary>
/// <param name="number"></param>
/// <param name="nearest"></param>
/// <returns></returns>
public static int RoundToNearest(int number, IEnumerable<int> nearest)
{
if (nearest == null)
throw new ArgumentNullException("nearest");
return nearest.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y);
}
/// <summary>
/// Gets a new, unique id given a sequence of existing ids.
/// </summary>
/// <param name="existingIds"></param>
/// <returns></returns>
public static int GetNewId(IEnumerable<int> existingIds)
{
if (existingIds == null)
throw new ArgumentNullException("existingIds");
IcdHashSet<int> existing = existingIds.ToHashSet();
return Enumerable.Range(1, int.MaxValue).First(i => !existing.Contains(i));
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils
{
/// <summary>
/// Provides util methods for working with file/directory paths.
/// </summary>
public static class PathUtils
{
#region Properties
/// <summary>
/// Gets the path to the root directory of the processor.
/// </summary>
[PublicAPI]
public static string RootPath { get { return IcdDirectory.GetDirectoryRoot("\\"); } }
/// <summary>
/// Gets the path to the NVRAM directory.
/// </summary>
[PublicAPI]
public static string NvramPath { get { return Join(RootPath, "NVRAM"); } }
/// <summary>
/// Returns the absolute path to the configuration directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string ProgramConfigPath
{
get
{
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
return Join(NvramPath, directoryName);
}
}
/// <summary>
/// Returns the absolute path to the common configuration directory.
/// </summary>
[PublicAPI]
public static string CommonConfigPath { get { return Join(NvramPath, "CommonConfig"); } }
/// <summary>
/// Returns the absolute path to the common config library directory.
/// </summary>
[PublicAPI]
public static string CommonLibPath { get { return Join(CommonConfigPath, "Lib"); } }
/// <summary>
/// Returns the absolute path to the program config library directory.
/// </summary>
[PublicAPI]
public static string ProgramLibPath { get { return Join(ProgramConfigPath, "Lib"); } }
#endregion
#region Methods
/// <summary>
/// Creates a path from the given path nodes.
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static string Join(params string[] items)
{
try
{
return items.Skip(1).Aggregate(items.First(), IcdPath.Combine);
}
catch (ArgumentException e)
{
throw new ArgumentException("Failed to join path: " + StringUtils.ArrayFormat(items), e);
}
}
/// <summary>
/// Gets the full path for the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFullPath(string path)
{
return Join(IcdDirectory.GetApplicationDirectory(), path);
}
/// <summary>
/// Replaces the filename while leaving the directory and extension intact.
/// </summary>
/// <param name="path"></param>
/// <param name="newName"></param>
/// <returns></returns>
public static string ChangeFilenameWithoutExt(string path, string newName)
{
string dir = IcdPath.GetDirectoryName(path);
string ext = IcdPath.GetExtension(path);
return Join(dir, newName + ext);
}
/// <summary>
/// Removes the extension from the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetPathWithoutExtension(string path)
{
string dir = IcdPath.GetDirectoryName(path);
string filename = IcdPath.GetFileNameWithoutExtension(path);
return Join(dir, filename);
}
/// <summary>
/// Recurses over the file paths at the given directory.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static IEnumerable<string> RecurseFilePaths(string path)
{
if (!IcdDirectory.Exists(path))
yield break;
Queue<string> queue = new Queue<string>();
queue.Enqueue(path);
while (queue.Count > 0)
{
path = queue.Dequeue();
// Get the subdirectories
try
{
foreach (string subDir in IcdDirectory.GetDirectories(path))
queue.Enqueue(subDir);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, e.Message);
}
// Get the files
string[] files;
try
{
files = IcdDirectory.GetFiles(path);
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, e.Message);
continue;
}
foreach (string filePath in files)
yield return filePath;
}
}
/// <summary>
/// Searches the program config path, common config path, and application path to
/// find the first config that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetDefaultConfigPath(params string[] localPath)
{
string local = Join(localPath);
// Program slot configuration
string programPath = Join(ProgramConfigPath, local);
if (PathExists(programPath))
return programPath;
// Common program configuration
string commonPath = Join(CommonConfigPath, local);
return PathExists(commonPath)
? commonPath
: Join(IcdDirectory.GetApplicationDirectory(), local); // Installation defaults
}
/// <summary>
/// Appends the local path to the program config path.
/// </summary>
/// <returns></returns>
public static string GetProgramConfigPath(params string[] localPath)
{
string local = Join(localPath);
return Join(ProgramConfigPath, local);
}
/// <summary>
/// Searches the application path, program config path and common config path to
/// find the first IR driver that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetIrDriversPath(params string[] localPath)
{
return GetDefaultConfigPath(localPath.Prepend("IRDrivers").ToArray());
}
/// <summary>
/// Searches the application path, program config path and common config path to
/// find the first SSL Driver that exists with the given local path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetSslCertificatesPath(params string[] localPath)
{
return GetDefaultConfigPath(localPath.Prepend("SSLCertificates").ToArray());
}
/// <summary>
/// Returns true if the given path exists.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static bool PathExists(string path)
{
return IcdFile.Exists(path) || IcdDirectory.Exists(path);
}
#endregion
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Text;
using ICD.Common.Properties;
namespace ICD.Common.Utils
{
/// <summary>
/// Utils for printing various data types in human readable structures.
/// </summary>
public static class PrettyPrint
{
#region Methods
[PublicAPI]
public static void PrintLine<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
IcdConsole.PrintLine(ToString(dictionary));
}
[PublicAPI]
public static void PrintLine<T>(IEnumerable<T> sequence)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
IcdConsole.PrintLine(ToString(sequence));
}
[PublicAPI]
public static string ToString<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
StringBuilder builder = new StringBuilder();
builder.AppendLine("{");
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
{
builder.Append('\t');
builder.Append(ToString(kvp.Key));
builder.Append(" : ");
builder.Append(ToString(kvp.Value));
builder.Append(',');
builder.AppendLine();
}
builder.Append("}");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(IEnumerable<T> sequence)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
StringBuilder builder = new StringBuilder();
builder.AppendLine("[");
foreach (T item in sequence)
{
builder.Append('\t');
builder.Append(ToString(item));
builder.Append(',');
builder.AppendLine();
}
builder.Append("]");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(T value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
return StringUtils.ToRepresentation(value == null ? null : value.ToString());
}
#endregion
}
}

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp;
#endif
using ICD.Common.Properties;
using ICD.Common.Services;
using ICD.Common.Services.Logging;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class ProgramUtils
{
private const string APPLICATION_NAME_KEY = "Application Name";
private const string APPLICATION_NAME_SIMPL_KEY = "System Name";
private const string PROGRAM_FILE_KEY = "Program File";
private const string COMPILED_ON_KEY = "Compiled On";
private const string COMPILER_REVISION_KEY = "Compiler Revision";
private const string COMPILER_REVISION_SIMPL_KEY = "Compiler Rev";
private static Dictionary<string, string> s_ProgComments;
#region Properties
/// <summary>
/// Lazy-load the prog-comments map.
/// </summary>
private static Dictionary<string, string> ProgComments
{
get { return s_ProgComments ?? (s_ProgComments = ParseProgComments()); }
}
/// <summary>
/// Gets the program number.
/// </summary>
[PublicAPI]
public static uint ProgramNumber
{
get
{
#if SIMPLSHARP
return InitialParametersClass.ApplicationNumber;
#else
return 1;
#endif
}
}
/// <summary>
/// Gets the program number in the format XX, eg slot 1 is 01.
/// </summary>
[PublicAPI]
public static string ProgramNumberFormatted { get { return string.Format("{0:D2}", ProgramNumber); } }
/// <summary>
/// Gets the compile date of the program.
/// </summary>
[PublicAPI]
public static string CompiledDate { get { return ProgComments.GetDefault(COMPILED_ON_KEY, null); } }
/// <summary>
/// Gets the compiler revision version.
/// </summary>
[PublicAPI]
public static Version CompilerRevision
{
get
{
string output;
if (ProgComments.TryGetValue(COMPILER_REVISION_KEY, out output))
return new Version(output);
if (ProgComments.TryGetValue(COMPILER_REVISION_SIMPL_KEY, out output))
return new Version(output);
return new Version(0, 0);
}
}
/// <summary>
/// Gets the name of the program dll.
/// </summary>
[PublicAPI]
public static string ProgramFile { get { return ProgComments.GetDefault(PROGRAM_FILE_KEY, null); } }
/// <summary>
/// Gets the name of the application.
/// </summary>
[PublicAPI]
public static string ApplicationName
{
get
{
string output;
if (ProgComments.TryGetValue(APPLICATION_NAME_KEY, out output))
return output;
ProgComments.TryGetValue(APPLICATION_NAME_SIMPL_KEY, out output);
return output;
}
}
#endregion
/// <summary>
/// Fakes program info, e.g. "Min Firmware Version : 1.009.0029"
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
[PublicAPI]
public static void PrintProgramInfoLine(string name, object value)
{
name = (name ?? string.Empty).Trim();
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
int length = Math.Min(13, name.Length);
name = name.Substring(0, length).PadRight(13);
break;
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
int proLength = Math.Min(26 - 1, name.Length);
name = name.Substring(0, proLength).PadRight(26);
break;
case IcdEnvironment.eRuntimeEnvironment.Standard:
name += ' ';
break;
default:
throw new ArgumentOutOfRangeException();
}
IcdConsole.PrintLine("{0}: {1}", name, value);
}
/// <summary>
/// Parses the prog comments and pulls program information.
/// </summary>
private static Dictionary<string, string> ParseProgComments()
{
Dictionary<string, string> output = new Dictionary<string, string>();
try
{
string progInfo = string.Empty;
string command = string.Format("progcomments:{0}", ProgramNumber);
if (!IcdConsole.SendControlSystemCommand(command, ref progInfo))
{
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Warning, "Failed to parse prog comments");
return output;
}
foreach (string line in progInfo.Split(new[] {"\n\r", "\r\n", "\n", "\r"}))
{
string[] pair = line.Split(':', 2).ToArray();
string key = pair[0].Trim();
string value = pair[1].Trim();
output[key] = value;
}
}
catch (Exception e)
{
ServiceProvider.TryGetService<ILoggerService>()
.AddEntry(eSeverity.Error, e, "Failed to parse prog comments - {0}", e.Message);
}
return output;
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
using Activator = Crestron.SimplSharp.Reflection.Activator;
#else
using System.IO;
using System.Reflection;
using Microsoft.Extensions.DependencyModel;
using System.Runtime.Loader;
using Activator = System.Activator;
#endif
namespace ICD.Common.Utils
{
public static class ReflectionUtils
{
/// <summary>
/// Instantiates the given type using the constructor matching the given values.
/// </summary>
/// <param name="type"></param>
/// <param name="values"></param>
/// <returns></returns>
[PublicAPI]
public static object Instantiate(Type type, params object[] values)
{
if (type == null)
throw new ArgumentNullException("type");
#if SIMPLSHARP
CType[] types = values.Select(v => (CType)v.GetType())
.ToArray();
ConstructorInfo constructor = ((CType)type).GetConstructor(types);
#else
Type[] types = values.Select(v => v.GetType())
.ToArray();
ConstructorInfo constructor = type.GetTypeInfo().GetConstructor(types);
#endif
if (constructor != null)
return constructor.Invoke(values);
string message = string.Format("Unable to find constructor for {0}", type.Name);
throw new InvalidOperationException(message);
}
/// <summary>
/// Returns true if the parameters match the method parameters.
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static bool MatchesMethodParameters(MethodBase method, IEnumerable<object> parameters)
{
if (method == null)
throw new ArgumentNullException("method");
if (parameters == null)
throw new ArgumentNullException("parameters");
#if SIMPLSHARP
CType[] methodTypes
#else
Type[] methodTypes
#endif
= method.GetParameters().Select(p => p.ParameterType).ToArray();
return ParametersMatchTypes(methodTypes, parameters);
}
/// <summary>
/// Returns true if the if the parameter match the property parameter.
/// </summary>
/// <param name="property"></param>
/// <param name="parameter"></param>
/// <returns></returns>
public static bool MatchesPropertyParameter(PropertyInfo property, object parameter)
{
if (property == null)
throw new ArgumentNullException("property");
#if SIMPLSHARP
CType propertyType
#else
Type propertyType
#endif
= property.PropertyType;
return ParametersMatchTypes(new[] {propertyType}, new[] {parameter});
}
/// <summary>
/// Returns true if the parameters array is compatible with the given property types array.
/// </summary>
/// <param name="types"></param>
/// <param name="parameters"></param>
/// <returns></returns>
#if SIMPLSHARP
private static bool ParametersMatchTypes(IEnumerable<CType> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
CType[] typesArray = types as CType[] ?? types.ToArray();
#else
private static bool ParametersMatchTypes(IEnumerable<Type> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
Type[] typesArray = types as Type[] ?? types.ToArray();
#endif
if (parameters == null)
throw new ArgumentNullException("parameters");
object[] parametersArray = parameters as object[] ?? parameters.ToArray();
if (parametersArray.Length != typesArray.Length)
return false;
// Compares each pair of items in the two arrays.
return !parametersArray.Where((t, index) => !ParameterMatchesType(typesArray[index], t)).Any();
}
/// <summary>
/// Returns true if the parameter can be assigned to the given type.
/// </summary>
/// <param name="type"></param>
/// <param name="parameter"></param>
/// <returns></returns>
#if SIMPLSHARP
private static bool ParameterMatchesType(CType type, object parameter)
{
if (type == null)
throw new ArgumentNullException("type");
// Can the parameter be assigned a null value?
if (parameter == null)
return (type.IsClass || !type.IsValueType || Nullable.GetUnderlyingType(type) != null);
return type.IsInstanceOfType(parameter);
}
#else
private static bool ParameterMatchesType(Type type, object parameter)
{
if (type == null)
throw new ArgumentNullException("type");
TypeInfo info = type.GetTypeInfo();
// Can the parameter be assigned a null value?
if (parameter == null)
return (info.IsClass || !info.IsValueType || Nullable.GetUnderlyingType(type) != null);
return info.IsInstanceOfType(parameter);
}
#endif
/// <summary>
/// Same as doing default(Type).
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
#if SIMPLSHARP
public static object GetDefaultValue(CType type)
#else
public static object GetDefaultValue(Type type)
#endif
{
if (type == null)
throw new ArgumentNullException("type");
return type
#if !SIMPLSHARP
.GetTypeInfo()
#endif
.IsValueType
? Activator.CreateInstance(type)
: null;
}
/// <summary>
/// Creates an instance of the given type, calling the default constructor.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T CreateInstance<T>()
where T : new()
{
return Activator.CreateInstance<T>();
}
/// <summary>
/// Gets the custom attributes added to the given assembly.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assembly"></param>
/// <returns></returns>
public static IEnumerable<object> GetCustomAttributes<T>(Assembly assembly)
where T : Attribute
{
if (assembly == null)
throw new ArgumentNullException("assembly");
#if SIMPLSHARP
return assembly.GetCustomAttributes(typeof(T), false);
#else
return assembly.GetCustomAttributes<T>();
#endif
}
/// <summary>
/// Loads the assembly at the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static Assembly LoadAssemblyFromPath(string path)
{
#if SIMPLSHARP
return Assembly.LoadFrom(path);
#else
string fileNameWithOutExtension = Path.GetFileNameWithoutExtension(path);
bool inCompileLibraries = DependencyContext.Default.CompileLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));
bool inRuntimeLibraries = DependencyContext.Default.RuntimeLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));
return inCompileLibraries || inRuntimeLibraries
? Assembly.Load(new AssemblyName(fileNameWithOutExtension))
: AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
#endif
}
}
}

View File

@@ -0,0 +1,65 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
namespace ICD.Common.Utils
{
/// <summary>
/// CCriticalSection tends to get disposed before the parent is done with it.
/// This class is an attempt to gracefully handle the ObjectDisposedExceptions we see on
/// program termination, ocassionally causing the program to restart instead of stop.
/// </summary>
public sealed partial class SafeCriticalSection
{
private readonly CCriticalSection m_CriticalSection;
/// <summary>
/// Constructor.
/// </summary>
public SafeCriticalSection()
{
m_CriticalSection = new CCriticalSection();
}
#region Methods
/// <summary>
/// Block until ownership of the critical section can be obtained.
/// </summary>
public void Enter()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return;
m_CriticalSection.Enter();
}
/// <summary>
/// Release ownership of the critical section.
/// </summary>
public void Leave()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return;
m_CriticalSection.Leave();
}
/// <summary>
/// Attempt to enter the critical section without blocking.
/// </summary>
/// <returns>
/// True, calling thread has ownership of the critical section; otherwise, false.
/// </returns>
public bool TryEnter()
{
if (m_CriticalSection == null || m_CriticalSection.Disposed)
return false;
return m_CriticalSection.TryEnter();
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,51 @@
#if !SIMPLSHARP
using System.Threading;
namespace ICD.Common.Utils
{
public sealed partial class SafeCriticalSection
{
private readonly Mutex m_Mutex;
/// <summary>
/// Constructor.
/// </summary>
public SafeCriticalSection()
{
m_Mutex = new Mutex();
}
#region Methods
/// <summary>
/// Block until ownership of the critical section can be obtained.
/// </summary>
public void Enter()
{
m_Mutex.WaitOne();
}
/// <summary>
/// Release ownership of the critical section.
/// </summary>
public void Leave()
{
m_Mutex.ReleaseMutex();
}
/// <summary>
/// Attempt to enter the critical section without blocking.
/// </summary>
/// <returns>
/// True, calling thread has ownership of the critical section; otherwise, false.
/// </returns>
public bool TryEnter()
{
return m_Mutex.WaitOne(0);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,49 @@
using System;
namespace ICD.Common.Utils
{
public sealed partial class SafeCriticalSection
{
/// <summary>
/// Enters the critical section, executes the callback and leaves the section.
/// </summary>
/// <param name="callback"></param>
public void Execute(Action callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
try
{
Enter();
callback();
}
finally
{
Leave();
}
}
/// <summary>
/// Enters the critical section, executes the callback and leaves the section.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="callback"></param>
/// <returns></returns>
public T Execute<T>(Func<T> callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
try
{
Enter();
return callback();
}
finally
{
Leave();
}
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Threading;
#endif
namespace ICD.Common.Utils
{
/// <summary>
/// Like the CCriticalSection, the CMutex tends to get disposed before the parent is
/// done with it. This class is an attempt to gracefully handle the ObjectDisposedExceptions
/// we see on program termination, ocassionally causing the program to restart instead of stop.
/// </summary>
public sealed class SafeMutex
{
#if SIMPLSHARP
private readonly CMutex m_Mutex;
#else
private readonly Mutex m_Mutex;
#endif
/// <summary>
/// Constructor.
/// </summary>
public SafeMutex()
{
#if SIMPLSHARP
m_Mutex = new CMutex();
#else
m_Mutex = new Mutex();
#endif
}
#region Methods
/// <summary>
/// Waits the given number of milliseconds to aquire the mutex.
/// </summary>
/// <param name="timeout"></param>
/// <returns>True if the mutex was aquired.</returns>
public bool WaitForMutex(int timeout)
{
try
{
#if SIMPLSHARP
return m_Mutex.WaitForMutex(timeout);
#else
return m_Mutex.WaitOne(timeout);
#endif
}
catch (ObjectDisposedException)
{
return false;
}
}
/// <summary>
/// Releases the mutex.
/// </summary>
public void ReleaseMutex()
{
try
{
m_Mutex.ReleaseMutex();
}
catch (ObjectDisposedException)
{
}
}
#endregion
}
}

View File

@@ -0,0 +1,477 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static class StringUtils
{
private const ushort ASCII_READABLE_START = 32;
private const ushort ASCII_READABLE_END = 126;
/// <summary>
/// Returns the number as a string in the format "\\x00"
/// </summary>
/// <param name="numeric"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(int numeric)
{
return string.Format("\\x{0:X2}", numeric);
}
/// <summary>
/// Returns the character as a string in the format "\\x00"
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(char c)
{
return ToHexLiteral(Convert.ToInt32(c));
}
/// <summary>
/// Returns a string as a string in the format "\\x00\\x00..."
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string ToHexLiteral(string input)
{
string[] strings = input.Select(c => ToHexLiteral(c)).ToArray();
return string.Join("", strings);
}
/// <summary>
/// Converts a character in the string format "\\x00" to char.
/// </summary>
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static char FromHexLiteralCharacter(string character)
{
string hexValue = character.Substring(2);
return (char)Convert.ToByte(hexValue, 16);
}
/// <summary>
/// Converts a string in the format "\\x00\\x00..." to hex representation.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
[PublicAPI]
public static string FromHexLiteral(string data)
{
return string.Join("", data.Split(4).Select(s => FromHexLiteralCharacter(s).ToString()).ToArray());
}
/// <summary>
/// Converts the char to a human readable character, otherwise returns a hex string
/// in the format "\x00"
/// </summary>
/// <param name="c"></param>
/// <returns></returns>
[PublicAPI]
public static string ToMixedReadableHexLiteral(char c)
{
int numeric = Convert.ToInt32(c);
if (numeric >= ASCII_READABLE_START && numeric <= ASCII_READABLE_END)
return c.ToString();
return ToHexLiteral(c);
}
/// <summary>
/// Converts the input string to a string in the format "\x00\x00" with human
/// readable characters where possible e.g. "Hello World!x\0D"
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string ToMixedReadableHexLiteral(string input)
{
string[] strings = input.Select(c => ToMixedReadableHexLiteral(c)).ToArray();
return string.Join("", strings);
}
/// <summary>
/// Converts bytes to an ascii string.
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
[PublicAPI]
public static string ToString(IEnumerable<byte> bytes)
{
byte[] cast = bytes as byte[] ?? bytes.ToArray();
return Encoding.UTF8.GetString(cast, 0, cast.Length);
}
/// <summary>
/// Converts bytes to an ascii string.
/// </summary>
/// <param name="bytes"></param>
/// <param name="length"></param>
/// <returns></returns>
[PublicAPI]
public static string ToString(IEnumerable<byte> bytes, int length)
{
byte[] cast = bytes as byte[] ?? bytes.ToArray();
return Encoding.UTF8.GetString(cast, 0, length);
}
/// <summary>
/// Converts an ascii string to bytes.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static byte[] ToBytes(string input)
{
return Encoding.UTF8.GetBytes(input);
}
/// <summary>
/// Attempts to parse the string as an integer.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out int result)
{
return TryConvert(Convert.ToInt32, value, out result);
}
/// <summary>
/// Attempts to parse the string as an unsigned integer.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out uint result)
{
return TryConvert(Convert.ToUInt32, value, out result);
}
/// <summary>
/// Attempts to parse the string as a float.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out float result)
{
return TryConvert(Convert.ToSingle, value, out result);
}
/// <summary>
/// Attempts to parse the string as a bool.
/// </summary>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryParse(string value, out bool result)
{
return TryConvert(Convert.ToBoolean, value, out result);
}
/// <summary>
/// Attempts to parse the string via the given conversion function.
/// </summary>
/// <param name="convertFunc"></param>
/// <param name="value"></param>
/// <param name="result"></param>
/// <returns></returns>
private static bool TryConvert<T>(Func<string, T> convertFunc, string value, out T result)
{
if (convertFunc == null)
throw new ArgumentNullException("convertFunc");
result = default(T);
bool retVal = false;
try
{
result = convertFunc(value);
retVal = true;
}
catch (FormatException)
{
}
catch (InvalidCastException)
{
}
return retVal;
}
/// <summary>
/// Returns the object.ToString() with spaces before capital letters.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string NiceName(object obj)
{
return NiceName(obj.ToString());
}
/// <summary>
/// Inserts spaces before capital letters.
///
/// http://stackoverflow.com/questions/4488969/split-a-string-by-capital-letters
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string NiceName(string name)
{
Regex regex = new Regex(@"
(?<=[A-Z])(?=[A-Z][a-z]) |
(?<=[^A-Z])(?=[A-Z]) |
(?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
return regex.Replace(name, " ");
}
/// <summary>
/// String.Format({0:######}) is unreliable if the number starts with a 0.
/// This method fills an input pattern #### from right to left with characters
/// from the number.
/// </summary>
/// <param name="phoneFormat"></param>
/// <param name="number"></param>
/// <returns></returns>
public static string SafeNumericFormat(string phoneFormat, string number)
{
phoneFormat = Reverse(phoneFormat);
number = Reverse(number);
StringBuilder builder = new StringBuilder();
int index = 0;
foreach (char c in phoneFormat)
{
if (index >= number.Length)
{
if (c == '#')
break;
builder.Append(c);
continue;
}
if (c == '#')
{
builder.Append(number[index]);
index++;
}
else
builder.Append(c);
}
return Reverse(builder.ToString()).TrimStart();
}
/// <summary>
/// Reverses the string.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string Reverse(string input)
{
char[] charArray = input.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
/// <summary>
/// Repeats the char the given number of times.
/// </summary>
/// <param name="input"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string Repeat(char input, int count)
{
return Repeat(input.ToString(), count);
}
/// <summary>
/// Repeats the string the given number of times.
/// </summary>
/// <param name="input"></param>
/// <param name="count"></param>
/// <returns></returns>
[PublicAPI]
public static string Repeat(string input, int count)
{
return count == 0 ? string.Empty : new StringBuilder().Insert(0, input, count).ToString();
}
/// <summary>
/// Returns each item.ToString() in the format "[item1, item2, item3...]"
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayFormat<T>(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
return string.Format("[{0}]", string.Join(", ", items.Select(i => i.ToString()).ToArray()));
}
/// <summary>
/// Given a sequence of numbers, generates a human readable list of numeric ranges.
/// E.g. [1, 2, 3, 5, 6] becomes "[1-3, 5-6]".
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayRangeFormat(IEnumerable<int> items)
{
if (items == null)
throw new ArgumentNullException("items");
string[] ranges = MathUtils.GetRanges(items)
.Select(r => r[0] == r[1]
? r[0].ToString()
: string.Format("{0}-{1}", r[0], r[1]))
.ToArray();
return ArrayFormat(ranges);
}
/// <summary>
/// Given a sequence of numbers, generates a human readable list of numeric ranges.
/// E.g. [1, 2, 3, 5, 6] becomes "[1-3, 5-6]".
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static string ArrayRangeFormat(IEnumerable<ushort> items)
{
if (items == null)
throw new ArgumentNullException("items");
return ArrayRangeFormat(items.Select(i => (int)i));
}
/// <summary>
/// Returns a pair of numbers in the format [a - b]
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
[PublicAPI]
public static string RangeFormat(object a, object b)
{
return string.Format("[{0} - {1}]", a, b);
}
/// <summary>
/// Capitalizes the first character of the string.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[PublicAPI]
public static string UppercaseFirst(string input)
{
if (string.IsNullOrEmpty(input))
return input;
return char.ToUpper(input[0]) + input.Substring(1);
}
/// <summary>
/// Formats an IPID to "0xFF"
/// </summary>
/// <param name="ipid"></param>
/// <returns></returns>
public static string ToIpIdString(byte ipid)
{
return string.Format("0x{0:X2}", ipid);
}
/// <summary>
/// Formats "0xFF" to an IPID.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static byte FromIpIdString(string value)
{
value = value.Replace("0x", "");
return Convert.ToByte(value, 16);
}
/// <summary>
/// Removes all whitespace from the string.
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string RemoveWhitespace(string text)
{
return text == null ? null : new string(text.Where(c => !Char.IsWhiteSpace(c)).ToArray());
}
/// <summary>
/// Returns the password as a series of *s
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public static string PasswordFormat(string password)
{
return password == null ? null : Repeat('*', password.Length);
}
/// <summary>
/// Pads the given string with quotations for readable type clarity. If the string is null, returns "NULL".
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToRepresentation(string value)
{
return value == null ? "NULL" : string.Format("\"{0}\"", value);
}
/// <summary>
/// Returns the items in the format "x, y, and z"
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
public static string SerialComma(IEnumerable<string> items)
{
if (items == null)
throw new ArgumentNullException("items");
string previous = null;
StringBuilder builder = new StringBuilder();
foreach (string item in items)
{
if (previous != null)
builder.AppendFormat("{0}, ", previous);
previous = item;
}
if (previous != null)
{
if (builder.Length > 0)
builder.AppendFormat("and {0}", previous);
else
builder.Append(previous);
}
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
/// <summary>
/// TableBuilder provides a way to format a collection of strings to a table.
/// </summary>
public sealed class TableBuilder
{
private const char HORIZONTAL = '-';
private const char VERTICAL = '|';
private readonly List<string[]> m_Rows;
private readonly SafeCriticalSection m_RowsSection;
private readonly string[] m_Columns;
/// <summary>
/// Gets the columns.
/// </summary>
[PublicAPI]
public string[] Columns { get { return m_Columns; } }
/// <summary>
/// Gets the number of columns.
/// </summary>
[PublicAPI]
public int ColumnsCount { get { return m_Columns.Length; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="columns"></param>
public TableBuilder(params string[] columns)
{
m_Rows = new List<string[]>();
m_RowsSection = new SafeCriticalSection();
m_Columns = columns;
}
#region Methods
/// <summary>
/// Clears all of the rows.
/// </summary>
[PublicAPI]
public void ClearRows()
{
m_RowsSection.Execute(() => m_Rows.Clear());
}
/// <summary>
/// Calls ToString() for each item and adds the row to the builder.
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params object[] row)
{
string[] stringRow = row.Select(o => string.Format("{0}", o))
.ToArray();
AddRow(stringRow);
}
/// <summary>
/// Adds the row to the builder.
/// </summary>
/// <param name="row"></param>
[PublicAPI]
public void AddRow(params string[] row)
{
if (row != null && row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
m_RowsSection.Execute(() => m_Rows.Add(row));
}
/// <summary>
/// Adds an empty row to the builder.
/// </summary>
[PublicAPI]
public void AddEmptyRow()
{
AddRow(new string[m_Columns.Length]);
}
[PublicAPI]
public void AddSeparator()
{
AddRow(null);
}
[PublicAPI]
public void AddHeader(params string[] row)
{
if (row.Length != m_Columns.Length)
throw new ArgumentException("Row must match columns length.");
AddSeparator();
AddRow(row);
AddSeparator();
}
/// <summary>
/// Gets the output string.
/// </summary>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
m_RowsSection.Enter();
try
{
int[] columnWidths = GetColumnWidths();
AppendRow(sb, m_Columns, columnWidths);
AppendSeparator(sb, columnWidths);
foreach (string[] row in m_Rows)
{
if (row == null)
AppendSeparator(sb, columnWidths);
else
AppendRow(sb, row, columnWidths);
}
AppendSeparator(sb, columnWidths);
}
finally
{
m_RowsSection.Leave();
}
return sb.ToString();
}
#endregion
#region Private Methods
private int[] GetColumnWidths()
{
int[] columnWidths = new int[m_Columns.Length];
for (int index = 0; index < m_Columns.Length; index++)
columnWidths[index] = GetColumnWidth(index);
return columnWidths;
}
private int GetColumnWidth(int index)
{
int titleLength = m_Columns[index].Length + 1;
if (m_Rows.Count == 0)
return titleLength;
int maxColumnWidth = m_Rows.Except((string[])null)
.Max(x => x[index] != null ? x[index].Length : 0) + 1;
return (titleLength > maxColumnWidth) ? titleLength : maxColumnWidth;
}
private static void AppendRow(StringBuilder builder, IList<string> row, IList<int> columnWidths)
{
for (int index = 0; index < row.Count; index++)
{
if (index > 0)
builder.Append(' ');
string value = row[index] ?? string.Empty;
builder.Append(value.PadRight(columnWidths[index]));
if (index < row.Count - 1)
builder.Append(VERTICAL);
}
builder.AppendLine();
}
private static void AppendSeparator(StringBuilder sb, ICollection<int> columnWidths)
{
int length = columnWidths.Sum() + (columnWidths.Count - 1) * 2;
string line = new string(HORIZONTAL, length);
sb.AppendLine(line);
}
#endregion
}
}

View File

@@ -0,0 +1,67 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Diagnostics;
#endif
namespace ICD.Common.Utils.Timers
{
public sealed class IcdStopwatch
{
private readonly Stopwatch m_Stopwatch;
#region Properties
public long ElapsedMilliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdStopwatch()
: this(new Stopwatch())
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stopwatch"></param>
public IcdStopwatch(Stopwatch stopwatch)
{
m_Stopwatch = stopwatch;
}
public static IcdStopwatch StartNew()
{
return new IcdStopwatch(Stopwatch.StartNew());
}
#endregion
#region Methods
public void Stop()
{
m_Stopwatch.Stop();
}
public void Start()
{
m_Stopwatch.Start();
}
public void Reset()
{
m_Stopwatch.Reset();
}
#endregion
}
}

View File

@@ -0,0 +1,166 @@
using System;
using ICD.Common.EventArguments;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// IcdTimer provides events for time increments as well as timer elapsed.
/// </summary>
public sealed class IcdTimer : IDisposable
{
private const long DEFAULT_HEARTBEAT_INTERVAL = 500;
/// <summary>
/// Called when the timer is restarted/stopped.
/// </summary>
public event EventHandler<BoolEventArgs> OnIsRunningChanged;
/// <summary>
/// Called when the timer has elapsed.
/// </summary>
public event EventHandler OnElapsed;
/// <summary>
/// Called when the milliseconds count changes. Useful for updating UIs.
/// </summary>
public event EventHandler OnMillisecondsChanged;
private readonly IcdStopwatch m_Stopwatch;
private readonly SafeTimer m_Heartbeat;
private long m_LastHeartbeatMilliseconds;
#region Properties
/// <summary>
/// Returns true if the timer is stopped.
/// </summary>
public bool IsStopped { get { return !m_Stopwatch.IsRunning; } }
/// <summary>
/// Returns true if the timer is running.
/// </summary>
public bool IsRunning { get { return m_Stopwatch.IsRunning; } }
/// <summary>
/// Returns true if the timer has elapsed.
/// </summary>
public bool IsElapsed { get { return Milliseconds > Length; } }
/// <summary>
/// Returns the number of milliseconds that have passed since the timer started.
/// </summary>
public long Milliseconds { get { return m_Stopwatch.ElapsedMilliseconds; } }
/// <summary>
/// The number of milliseconds before the timer is elapsed.
/// </summary>
public long Length { get; private set; }
/// <summary>
/// Gets the remaining number of milliseconds until the timer is elapsed. Returns 0 if the timer has elapsed.
/// </summary>
public long Remaining { get { return Math.Max(Length - Milliseconds, 0); } }
/// <summary>
/// Gets the remaining number of seconds until the timer is elapsed. Returns 0 if the timer has elapsed.
/// </summary>
public long RemainingSeconds { get { return (long)Math.Ceiling(Remaining / 1000.0f); } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public IcdTimer()
: this(DEFAULT_HEARTBEAT_INTERVAL)
{
}
/// <summary>
/// Creates an IcdTimer with the specified heartbeat interval for the internal timer.
/// This allows a finer resolution for timing than the default 500ms.
/// </summary>
/// <param name="heartbeatInterval"></param>
public IcdTimer(long heartbeatInterval)
{
m_Heartbeat = new SafeTimer(HeartbeatCallback, heartbeatInterval, heartbeatInterval);
m_Stopwatch = new IcdStopwatch();
Stop();
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
OnIsRunningChanged = null;
OnElapsed = null;
OnMillisecondsChanged = null;
m_Stopwatch.Stop();
m_Heartbeat.Dispose();
}
/// <summary>
/// Restarts the timer.
/// </summary>
public void Restart(long length)
{
Length = length;
m_Stopwatch.Reset();
m_Stopwatch.Start();
RaiseOnIsRunningChanged();
}
/// <summary>
/// Stops the timer.
/// </summary>
public void Stop()
{
m_Stopwatch.Stop();
RaiseOnIsRunningChanged();
}
#endregion
#region Private Methods
/// <summary>
/// Called when the heartbeat timer elapses.
/// </summary>
private void HeartbeatCallback()
{
if (Milliseconds == m_LastHeartbeatMilliseconds)
return;
OnMillisecondsChanged.Raise(this);
if (m_LastHeartbeatMilliseconds <= Length && IsElapsed)
OnElapsed.Raise(this);
m_LastHeartbeatMilliseconds = Milliseconds;
}
/// <summary>
/// Raises the OnIsRunningChanged event.
/// </summary>
private void RaiseOnIsRunningChanged()
{
OnIsRunningChanged.Raise(this, new BoolEventArgs(IsRunning));
}
#endregion
}
}

View File

@@ -0,0 +1,100 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// Simple class for implementing things like volume ramps, where a button has an
/// immediate effect, and then begins ramping after a brief delay.
/// </summary>
[PublicAPI]
public sealed class Repeater : IDisposable
{
/// <summary>
/// Raised on the initial repeat.
/// </summary>
[PublicAPI]
public event EventHandler OnInitialRepeat;
/// <summary>
/// Raised on each subsequent repeat.
/// </summary>
[PublicAPI]
public event EventHandler OnRepeat;
private readonly SafeTimer m_RepeatTimer;
private readonly long m_BeforeRepeat;
private readonly long m_BetweenRepeat;
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="beforeRepeat">The delay before the second increment</param>
/// <param name="betweenRepeat">The delay between each subsequent repeat</param>
public Repeater(long beforeRepeat, long betweenRepeat)
{
m_RepeatTimer = SafeTimer.Stopped(RepeatCallback);
m_BeforeRepeat = beforeRepeat;
m_BetweenRepeat = betweenRepeat;
}
/// <summary>
/// Destructor.
/// </summary>
~Repeater()
{
Dispose();
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
m_RepeatTimer.Dispose();
}
/// <summary>
/// Begin repeating.
/// </summary>
[PublicAPI]
public void Start()
{
OnInitialRepeat.Raise(this);
m_RepeatTimer.Reset(m_BeforeRepeat, m_BetweenRepeat);
}
/// <summary>
/// Stop repeating volume.
/// </summary>
[PublicAPI]
public void Stop()
{
m_RepeatTimer.Stop();
}
#endregion
#region Private Methods
/// <summary>
/// Called for every repeat.
/// </summary>
private void RepeatCallback()
{
OnRepeat.Raise(this);
}
#endregion
}
}

View File

@@ -0,0 +1,180 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
#else
using System.Threading;
#endif
using ICD.Common.Services;
using ICD.Common.Services.Logging;
namespace ICD.Common.Utils.Timers
{
/// <summary>
/// SafeTimer wraps CTimer to hide some of the jank.
/// </summary>
public sealed class SafeTimer : IStateDisposable
{
#if SIMPLSHARP
private readonly CTimer m_Timer;
#else
private readonly Timer m_Timer;
private int m_DueTime, m_RepeatPeriod;
#endif
private readonly Action m_Callback;
/// <summary>
/// Returns true if this instance has been disposed.
/// </summary>
public bool IsDisposed { get; private set; }
#region Constructors
/// <summary>
/// Creates a timer that is called every repeatPeriod in milliseconds.
/// </summary>
/// <param name="callback"></param>
/// <param name="repeatPeriod"></param>
public SafeTimer(Action callback, long repeatPeriod)
: this(callback, 0, repeatPeriod)
{
}
/// <summary>
/// Creates a timer that is called in dueTime milliseconds and then every
/// repeatPeriod milliseconds afterwards.
/// </summary>
/// <param name="callback"></param>
/// <param name="dueTime"></param>
/// <param name="repeatPeriod"></param>
public SafeTimer(Action callback, long dueTime, long repeatPeriod)
{
m_Callback = callback;
#if SIMPLSHARP
m_Timer = new CTimer(SafeCallback, null, dueTime, repeatPeriod);
#else
m_DueTime = (int)dueTime;
m_RepeatPeriod = (int)repeatPeriod;
m_Timer = new Timer(SafeCallback, null, m_DueTime, m_RepeatPeriod);
#endif
}
/// <summary>
/// Creates a timer that is initially stopped.
/// </summary>
/// <param name="callback"></param>
/// <returns></returns>
public static SafeTimer Stopped(Action callback)
{
SafeTimer output = new SafeTimer(callback, 0);
output.Stop();
return output;
}
#endregion
#region Methods
/// <summary>
/// Release resources.
/// </summary>
public void Dispose()
{
Stop();
m_Timer.Dispose();
IsDisposed = true;
}
/// <summary>
/// Stops the timer.
/// </summary>
public void Stop()
{
#if SIMPLSHARP
m_Timer.Stop();
#else
m_Timer.Change(Timeout.Infinite, Timeout.Infinite);
#endif
}
/// <summary>
/// Immediately calls the callback and resets the timer
/// </summary>
public void Trigger()
{
#if SIMPLSHARP
m_Timer.Reset();
#else
m_Timer.Change(0, m_RepeatPeriod);
#endif
}
/// <summary>
/// Callback is called after the dueTime milliseconds.
/// </summary>
/// <param name="dueTime"></param>
public void Reset(long dueTime)
{
#if SIMPLSHARP
m_Timer.Reset(dueTime);
#else
m_DueTime = (int)dueTime;
m_Timer.Change(m_DueTime, m_RepeatPeriod);
#endif
}
/// <summary>
/// Callback is called after the dueTime milliseconds and every repeatPeriod milliseconds.
/// </summary>
/// <param name="dueTime"></param>
/// <param name="repeatPeriod"></param>
public void Reset(long dueTime, long repeatPeriod)
{
#if SIMPLSHARP
m_Timer.Reset(dueTime, repeatPeriod);
#else
m_DueTime = (int)dueTime;
m_RepeatPeriod = (int)repeatPeriod;
m_Timer.Change(m_DueTime, m_RepeatPeriod);
#endif
}
#endregion
#region Private Methods
/// <summary>
/// Only executes the callback if the timer has not been disposed.
/// Catches any exceptions and logs them.
/// </summary>
/// <param name="unused"></param>
private void SafeCallback(object unused)
{
// Essentially the meat of this class. There's some weirdness with the garbage collector where
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
// despite being stopped/disposed.
if (m_Timer == null
#if SIMPLSHARP
|| m_Timer.Disposed
#endif
)
return;
try
{
m_Callback();
}
catch (Exception e)
{
LogException(e);
}
}
private void LogException(Exception e)
{
string message = string.Format("{0} failed to execute callback - {1}", GetType().Name, e.Message);
ServiceProvider.TryGetService<ILoggerService>().AddEntry(eSeverity.Error, e, message);
}
#endregion
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace ICD.Common.Utils
{
public static class TryUtils
{
/// <summary>
///
/// </summary>
/// <typeparam name="TResult">return type</typeparam>
/// <param name="function"></param>
/// <param name="val"></param>
/// <returns></returns>
public static bool Try<TResult>(Func<TResult> function, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
try
{
val = function();
return true;
}
catch (Exception)
{
val = default(TResult);
return false;
}
}
public static bool Try<T1, TResult>(Func<T1, TResult> function, T1 param1, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1), out val);
}
public static bool Try<T1, T2, TResult>(Func<T1, T2, TResult> function, T1 param1, T2 param2, out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1, param2), out val);
}
public static bool Try<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 param1, T2 param2, T3 param3,
out TResult val)
{
if (function == null)
throw new ArgumentNullException("function");
return Try(() => function(param1, param2, param3), out val);
}
}
}

View File

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

View File

@@ -0,0 +1,101 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
namespace ICD.Common.Utils.Xml
{
public static class IcdXmlConvert
{
public static string ToString(int value)
{
return XmlConvert.ToString(value);
}
public static string ToString(bool value)
{
return XmlConvert.ToString(value);
}
public static string ToString(float value)
{
return XmlConvert.ToString(value);
}
public static string ToString(double value)
{
return XmlConvert.ToString(value);
}
public static string ToString(decimal value)
{
return XmlConvert.ToString(value);
}
public static string ToString(long value)
{
return XmlConvert.ToString(value);
}
public static string ToString(ulong value)
{
return XmlConvert.ToString(value);
}
public static string ToString(Guid value)
{
return XmlConvert.ToString(value);
}
public static string ToString(TimeSpan value)
{
return XmlConvert.ToString(value);
}
public static string ToString(int? value)
{
return value.HasValue ? ToString(value.Value) : null;
}
public static string ToString(object child)
{
if (child == null)
return null;
if (child is bool)
return ToString((bool)child);
if (child is byte)
return ToString((byte)child);
if (child is decimal)
return ToString((decimal)child);
if (child is char)
return ToString((char)child);
if (child is double)
return ToString((double)child);
if (child is Guid)
return ToString((Guid)child);
if (child is float)
return ToString((float)child);
if (child is int)
return ToString((int)child);
if (child is long)
return ToString((long)child);
if (child is sbyte)
return ToString((sbyte)child);
if (child is short)
return ToString((short)child);
if (child is TimeSpan)
return ToString((TimeSpan)child);
if (child is uint)
return ToString((uint)child);
if (child is ulong)
return ToString((ulong)child);
if (child is ushort)
return ToString((ushort)child);
return child.ToString();
}
}
}

View File

@@ -0,0 +1,40 @@
#if SIMPLSHARP
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlDocument
{
private readonly XmlDocument m_Document;
/// <summary>
/// Constructor.
/// </summary>
public IcdXmlDocument()
{
m_Document = new XmlDocument();
}
public void LoadXml(string xml)
{
try
{
m_Document.LoadXml(xml);
}
catch (XmlException e)
{
throw new IcdXmlException(e.Message, e, e.LineNumber, e.LinePosition);
}
}
public void WriteContentTo(IcdXmlTextWriter writer)
{
m_Document.WriteContentTo(writer.WrappedWriter);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlException : Exception
{
private int m_LineNumber;
private int m_LinePosition;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
/// <param name="lineNumber"></param>
/// <param name="linePosition"></param>
public IcdXmlException(string message, Exception inner, int lineNumber, int linePosition)
: base(message, inner)
{
m_LineNumber = lineNumber;
m_LinePosition = linePosition;
}
}
}

View File

@@ -0,0 +1,128 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
using System.IO;
#endif
namespace ICD.Common.Utils.Xml
{
public sealed class IcdXmlReader : IDisposable
{
private readonly XmlReader m_Reader;
#region Properties
public bool HasAttributes { get { return m_Reader.HasAttributes; } }
public string Name { get { return m_Reader.Name; } }
public string Value { get { return m_Reader.Value; } }
public XmlNodeType NodeType { get { return m_Reader.NodeType; } }
#endregion
/// <summary>
/// Constructor.
/// </summary>
/// <param name="xml"></param>
public IcdXmlReader(string xml)
{
if (xml == null)
throw new ArgumentNullException("xml");
#if SIMPLSHARP
m_Reader = new XmlReader(xml);
#else
m_Reader = XmlReader.Create(new StringReader(xml));
#endif
}
~IcdXmlReader()
{
Dispose();
}
#region Methods
public bool MoveToNextAttribute()
{
return m_Reader.MoveToNextAttribute();
}
public void MoveToElement()
{
m_Reader.MoveToElement();
}
public string GetAttribute(string name)
{
return m_Reader.GetAttribute(name);
}
public string ReadString()
{
#if SIMPLSHARP
return m_Reader.ReadString();
#else
return m_Reader.ReadElementContentAsString();
#endif
}
public bool Read()
{
try
{
return m_Reader.Read();
}
catch (XmlException e)
{
throw new IcdXmlException(e.Message, e, e.LineNumber, e.LinePosition);
}
}
public void Dispose()
{
#if SIMPLSHARP
m_Reader.Dispose(true);
#else
m_Reader.Dispose();
#endif
}
public void Skip()
{
m_Reader.Skip();
}
public string ReadElementContentAsString()
{
return m_Reader.ReadElementContentAsString();
}
public string ReadOuterXml()
{
return m_Reader.ReadOuterXml();
}
public string ReadInnerXml()
{
return m_Reader.ReadInnerXml();
}
public long ReadElementContentAsLong()
{
return m_Reader.ReadElementContentAsLong();
}
public float ReadElementContentAsFloat()
{
return m_Reader.ReadElementContentAsFloat();
}
#endregion
}
}

View File

@@ -0,0 +1,94 @@
#if SIMPLSHARP
using System.Text;
using Crestron.SimplSharp.CrestronXml;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter
{
private readonly XmlTextWriter m_Writer;
public XmlWriter WrappedWriter { get { return m_Writer; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
/// <param name="encoding"></param>
public IcdXmlTextWriter(IcdStream stream, Encoding encoding)
: this(new XmlTextWriter(stream.WrappedStream, encoding))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
public IcdXmlTextWriter(IcdTextWriter textWriter)
: this(new XmlTextWriter(textWriter.WrappedTextWriter))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="writer"></param>
public IcdXmlTextWriter(XmlTextWriter writer)
{
m_Writer = writer;
m_Writer.Formatting = Crestron.SimplSharp.CrestronXml.Formatting.Indented;
}
#region Methods
public void WriteStartElement(string elementName)
{
m_Writer.WriteStartElement(elementName);
}
public void WriteElementString(string elementName, string value)
{
m_Writer.WriteElementString(elementName, value);
}
public void WriteEndElement()
{
m_Writer.WriteEndElement();
}
public void WriteComment(string comment)
{
m_Writer.WriteComment(comment);
}
public void Dispose()
{
m_Writer.Dispose(true);
}
public void WriteAttributeString(string attributeName, string value)
{
m_Writer.WriteAttributeString(attributeName, value);
}
public void Flush()
{
m_Writer.Flush();
}
public void Close()
{
m_Writer.Close();
}
public void WriteRaw(string xml)
{
m_Writer.WriteRaw(xml);
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,102 @@
using System.Text;
using System.Xml;
using ICD.Common.Utils.IO;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter
{
private readonly XmlWriter m_Writer;
public XmlWriter WrappedWriter { get { return m_Writer; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
/// <param name="encoding"></param>
public IcdXmlTextWriter(IcdStream stream, Encoding encoding)
: this(XmlWriter.Create(stream.WrappedStream, GetSettings(encoding)))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="textWriter"></param>
public IcdXmlTextWriter(IcdTextWriter textWriter)
: this(XmlWriter.Create(textWriter.WrappedTextWriter))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="writer"></param>
public IcdXmlTextWriter(XmlWriter writer)
{
m_Writer = writer;
}
#region Methods
public void WriteStartElement(string elementName)
{
m_Writer.WriteStartElement(elementName);
}
public void WriteElementString(string elementName, string value)
{
m_Writer.WriteElementString(elementName, value);
}
public void WriteEndElement()
{
m_Writer.WriteEndElement();
}
public void WriteComment(string comment)
{
m_Writer.WriteComment(comment);
}
public void Dispose()
{
m_Writer.Dispose();
}
public void WriteAttributeString(string attributeName, string value)
{
m_Writer.WriteAttributeString(attributeName, value);
}
public void Flush()
{
m_Writer.Flush();
}
public void Close()
{
}
public void WriteRaw(string xml)
{
m_Writer.WriteRaw(xml);
}
#endregion
#region Private Methods
private static XmlWriterSettings GetSettings(Encoding encoding)
{
return new XmlWriterSettings
{
Encoding = encoding,
Indent = true
};
}
#endregion
}
}

View File

@@ -0,0 +1,8 @@
using System;
namespace ICD.Common.Utils.Xml
{
public sealed partial class IcdXmlTextWriter : IDisposable
{
}
}

View File

@@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronXml;
#else
using System.Xml;
#endif
using ICD.Common.EventArguments;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Xml
{
public static class XmlReaderExtensions
{
#region Attributes
/// <summary>
/// Returns true if the attribute exists.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static bool HasAttribute(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetAttribute(name) != null;
}
/// <summary>
/// Gets the attributes for the current element without moving the reader.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<IcdXmlAttribute> GetAttributes(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (!extends.HasAttributes)
return new IcdXmlAttribute[0];
List<IcdXmlAttribute> attributes = new List<IcdXmlAttribute>();
while (extends.MoveToNextAttribute())
attributes.Add(new IcdXmlAttribute(extends.Name, extends.Value));
// Move back to element.
extends.MoveToElement();
return attributes.ToArray();
}
/// <summary>
/// Gets the value of the attribute with the given name.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static string GetAttributeAsString(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string output = extends.GetAttribute(name);
if (output == null)
throw new FormatException(string.Format("Missing attribute \"{0}\"", name));
return output;
}
/// <summary>
/// Gets the value of the attribute with the given name and returns as an integer.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static int GetAttributeAsInt(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetAttributeAsString(name);
return int.Parse(value);
}
/// <summary>
/// Gets the value of the attribute with the given name and returns as a bool.
/// </summary>
/// <param name="extends"></param>
/// <param name="name"></param>
/// <returns></returns>
[PublicAPI]
public static bool GetAttributeAsBool(this IcdXmlReader extends, string name)
{
if (extends == null)
throw new ArgumentNullException("extends");
string value = extends.GetAttributeAsString(name);
return bool.Parse(value);
}
#endregion
#region Recurse
/// <summary>
/// Recurses through the entire XML, calling the callback for each Element/Text node.
/// </summary>
/// <param name="extends"></param>
/// <param name="callback"></param>
[PublicAPI]
public static void Recurse(this IcdXmlReader extends, Action<XmlRecursionEventArgs> callback)
{
if (extends == null)
throw new ArgumentNullException("extends");
XmlUtils.Recurse(extends.ReadString(), callback);
}
#endregion
#region Skip
/// <summary>
/// Skips over insignificant whitespace.
/// </summary>
/// <param name="extends"></param>
[PublicAPI]
public static void SkipInsignificantWhitespace(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.NodeType == XmlNodeType.Whitespace && extends.Read())
{
}
}
/// <summary>
/// Skips the current node to the next element.
/// </summary>
/// <param name="extends"></param>
[PublicAPI]
public static bool SkipToNextElement(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.Read() && extends.NodeType != XmlNodeType.Element)
{
}
return extends.NodeType == XmlNodeType.Element;
}
#endregion
#region Get Child Element
/// <summary>
/// Returns true if the current node has child elements.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool HasChildElements(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
while (extends.Read() && extends.NodeType != XmlNodeType.EndElement)
{
if (extends.NodeType == XmlNodeType.Element)
return true;
}
return false;
}
/// <summary>
/// Gets the child elements for the current element.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<IcdXmlReader> GetChildElements(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
foreach (IcdXmlReader output in extends.GetChildElementsAsString().Select(child => new IcdXmlReader(child)))
{
output.SkipToNextElement();
yield return output;
}
}
/// <summary>
/// Gets the child elements for the current element.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> GetChildElementsAsString(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Step into the first child.
extends.SkipToNextElement();
while (extends.NodeType == XmlNodeType.Element || extends.NodeType == XmlNodeType.Comment)
{
switch (extends.NodeType)
{
case XmlNodeType.Comment:
extends.Skip();
break;
case XmlNodeType.Element:
yield return extends.ReadOuterXml();
break;
}
extends.SkipInsignificantWhitespace();
}
}
#endregion
#region Read Element Content
/// <summary>
/// Parses the element content in the format 0xXX as a byte.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static byte ReadElementContentAsByte(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return (byte)Convert.ToInt64(content, 16);
}
/// <summary>
/// Parses the element content as a uint.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static uint ReadElementContentAsUint(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return uint.Parse(content);
}
/// <summary>
/// Parses the element content as a uint.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static int ReadElementContentAsInt(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return int.Parse(content);
}
/// <summary>
/// Parses the element content as a ushort.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static ushort ReadElementContentAsUShort(this IcdXmlReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return ushort.Parse(content);
}
/// <summary>
/// Parses the element content as an enum.
/// </summary>
/// <param name="extends"></param>
/// <param name="ignoreCase"></param>
/// <returns></returns>
[PublicAPI]
public static T ReadElementContentAsEnum<T>(this IcdXmlReader extends, bool ignoreCase)
{
if (extends == null)
throw new ArgumentNullException("extends");
string content = extends.ReadElementContentAsString();
return EnumUtils.Parse<T>(content, ignoreCase);
}
#endregion
}
}

File diff suppressed because it is too large Load Diff